30

我有一个 Grails 服务,它通过 HTTP 调用使用 3rd-party 服务发送电子邮件:

class EmailService {
    def sendEmail(values) {
        def valueJson = values as JSON
        ... // does HTTP call to 3rd party service
    }
}

我编写了一个单元测试来测试这个服务(因为集成测试启动了 Hibernate 和整个域框架,我不需要):

@TestFor(EmailService)
class EmailServiceTests {
    void testEmailServiceWorks() {
        def values = [test: 'test', test2: 'test2']
        service.sendEmail(values)
    }
}

但是,当我执行此单元测试时,它在尝试进行as JSON转换时失败并出现此异常:

org.apache.commons.lang.UnhandledException:org.codehaus.groovy.grails.web.converters.exceptions.ConverterException:类的不可转换对象:java.util.LinkedHashMap

然后我重新编写了我的单元测试来执行以下操作:

void testEmailServiceWorks() {
    def value = [test: 'test', test2: 'test2']
    def valueJson = value as JSON
}

as JSON当它尝试进行转换时,我得到了同样的异常。

有谁知道我为什么会遇到这个异常,以及如何解决它?

4

6 回答 6

71

即使您正在测试服务,您也可以将@TestMixin(ControllerUnitTestMixin)注释应用到您的测试类以让 Grails 设置 JSON 转换器。

于 2013-03-18T19:49:25.083 回答
10

as JSON 魔法是在域框架启动时创建的。

您必须将测试更改为集成测试或模拟 asType。

def setUp(){
    java.util.LinkedHashMap.metaClass.asType = { Class c ->
        new grails.converters."$c"(delegate)
    }
}

请记住在拆解过程中自己进行清理,您不希望测试套件中出现元编程泄漏。

def tearDown(){
    java.util.LinkedHashMap.metaClass.asType = null
}

编辑:如果您来自未来,请考虑以下答案:https ://stackoverflow.com/a/15485593/194932

于 2012-08-02T21:45:06.367 回答
7

由于 Grails 3.3.xgrails-test-mixins插件已被弃用。@see迁移指南

对于这个问题,您应该实施GrailsWebUnitTest来自Grails 测试支持框架的方法。

于 2018-07-12T13:21:59.513 回答
5

您可以在 setUp() 中初始化 JSON。有各种实现 ObjectMarshaller 的编组器,需要将它们添加到 ConverterConfiguration 才能使 JSON 转换工作。

http://grails.github.io/grails-doc/2.4.4/api/index.html?org/codehaus/groovy/grails/web/converters/marshaller/json/package-summary.html

例子 :

 DefaultConverterConfiguration<JSON> defaultConverterConfig = new  DefaultConverterConfiguration<JSON>()
 defaultConverterConfig.registerObjectMarshaller(new CollectionMarshaller())
 defaultConverterConfig.registerObjectMarshaller(new MapMarshaller())
 defaultConverterConfig.registerObjectMarshaller(new GenericJavaBeanMarshaller())

 ConvertersConfigurationHolder.setTheadLocalConverterConfiguration(JSON.class, defaultConverterConfig);
于 2012-08-05T18:20:18.937 回答
2

我刚刚遇到了这个问题,我真的不想GrailsWebUnitTest按照此处另一个答案中的建议实施。我想让我的服务测试尽可能“纯粹”和精简。我最终这样做了:

void setupSpec() {
    defineBeans(new ConvertersGrailsPlugin())
}

void cleanupSpec() {
    ConvertersConfigurationHolder.clear()
}

这就是当您实现GrailsWebUnitTest(通过WebSetupSpecInterceptorWebCleanupSpecInterceptor)时它在幕后发生的方式。


也就是说,转换器似乎是为在 Web 层中使用而设计的,主要是为了便于从控制器透明地返回不同格式的数据。值得考虑为什么您正在测试的服务首先需要转换器。

例如,在我的例子中,有人使用 JSON 转换器将一些数据序列化为字符串,以便将其存储在数据库的单个字段中。这似乎不是转换器的合适用户,所以我计划改变它的完成方式。在我的服务测试中提供转换器是一个临时解决方案,它允许我在重构之前提高我们的测试覆盖率。

于 2020-03-27T16:15:50.900 回答
1

尝试对调用“将 myMap 渲染为 JSON”的控制器进行单元测试时,我遇到了同样的错误。我们使用 Grails 1.3.7 并且没有其他解决方案对我有用而不引入其他问题。目前,升级 Grails 对我们来说不是一种选择。

我的解决方案是使用 JSONBuilder 而不是“as JSON”,如下所示:

render(contentType: "application/json", {myMap})

请参阅http://docs.grails.org/latest/guide/theWebLayer.html#moreOnJSONBuilder

(我意识到这已经过时了,但来这里是为了寻找解决方案,其他人也可能如此)

于 2016-07-15T10:40:25.090 回答