Spock - 存根 JSON 响应

Spock - stubbing the JSON response

我使用带有内置 spock 的 Grails 3.1.7。看起来我在对单元测试执行期间由控制器呈现的 return 服务值进行存根时遇到了麻烦。服务方法 returns null 然后控制器抛出 GroovyRuntimeException 抱怨 "Cannot resolve which method to invoke" 因为 "null" returned.

控制器动作代码示例:

def register(RequestRegistrationCommand rrc) {
    //some logic
    render ajaxResponseService.composeJsonResponse(rrc)
}

服务方法代码示例:

JSON composeJsonResponse(instance, String successMessage = null) {
    //some logic
    [success: success, messages: messages] as JSON
}

部分测试套件代码:

//field definitions
def requestRegistrationCommand = Mock(RequestRegistrationCommand)
def ajaxResponseService = Mock(AjaxResponseService)

def setup() {
    controller.ajaxResponseService = ajaxResponseService
    .....
}

void "Testing register() action"() {
    when: 'Passing invalid register params'
    ...
    params.email = INVALID_EMAIL
    controller.register(requestRegistrationCommand)

    then: 'JSON response returned'
    ...
    1 * ajaxResponseService.composeJsonResponse(requestRegistrationCommand) >> [asd:123] as JSON //tried plenty of things here
}

有趣的是交互本身被触发(通过将其替换为“0 * _”进行检查,并将“1 * ajaxR ... >> 'asd'”放入错误中字符串无法转换为 JSON)。因此,交互可能具有 return 一些存根值,但无论如何在大多数情况下,我尝试过控制器的行为就好像它试图呈现 null:

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method grails.artefact.controller.support.ResponseRenderer$Trait$Helper#render. Cannot resolve which method to invoke for [class com.tempvs.controllers.AuthController, null] due to overlapping prototypes between: [interface grails.artefact.controller.support.ResponseRenderer, interface java.lang.CharSequence] [interface grails.artefact.controller.support.ResponseRenderer, interface java.util.Map] [interface grails.artefact.controller.support.ResponseRenderer, interface org.grails.web.converters.Converter] at com.tempvs.controllers.AuthController.register(AuthController.groovy:45) at com.tempvs.controllers.AuthControllerSpec.Testing register() action(AuthControllerSpec.groovy:97)

我做错了什么以及我应该如何强制模拟服务对象 return 非空值以避免控制器渲染失败?

如果需要更多信息,请通知我,我尽量做到简短。提前致谢!

UPD 交互测试通过:

1 * ajaxResponseService.composeJsonResponse(requestRegistrationCommand) >> Mock(JSON)

当我将 AjaxResponseService#composeJsonResponse() return 类型从 JSON 更改为 def 时。但是来吧,我只使用一个模拟的协作者进行测试,我怎么能强制它支持显式类型?!?!

您应该为您的 return 值使用闭包:

1 * ajaxResponseService.composeJsonResponse(requestRegistrationCommand) >> { [asd:123] as JSON }

参见(请参阅有关 return 值的部分):

http://spockframework.org/spock/docs/1.1-rc-3/interaction_based_testing.html

您可以用括号将 return 括起来:

1 * ajaxResponseService.composeJsonResponse(requestRegistrationCommand) >> ( [asd:123] as JSON )

实际上我通过模拟 return 值解决了它:

def json = Mock(JSON)
....
1 * ajaxResponseService.composeJsonResponse(requestRegistrationCommand) >> json