Rest 如何在Grails2.4.3中的控制器中测试复合json对象响应

Rest 如何在Grails2.4.3中的控制器中测试复合json对象响应,rest,grails,testing,junit,spock,Rest,Grails,Testing,Junit,Spock,我正在测试Restful控制器的保存方法,CustomerController 客户,域类,有地址关联,地址有城市,城市有州,州有国家 我为地址编写了自定义封送拆收器和自定义绑定帮助器,因此JSON客户是这样的: { "id": "g2c3e08iqton4v5bsgti33gkpd35l0er", "firstName": "Bob1", "lastName": "Patiño1", "middleName": "The Payaso1", "email

我正在测试Restful控制器的保存方法,
CustomerController

客户,域类,有地址关联,地址有城市,城市有州,州有国家

我为
地址
编写了自定义封送拆收器和自定义绑定帮助器,因此JSON客户是这样的:

{
    "id": "g2c3e08iqton4v5bsgti33gkpd35l0er",
    "firstName": "Bob1",
    "lastName": "Patiño1",
    "middleName": "The Payaso1",
    "email": "me@bobpatino.org",
    "phoneNumber": "300555551",
    "address": {
        "addressLine1": "addressLine1",
        "postalCode": "110111",
        "city": {
            "name": "Bogotá",
            "state": "DC",
            "country": "CO"
        }
    }
}
一切都在使用这种格式工作,记住地址的自定义封送拆收器和绑定帮助器,但现在我想测试控制器

 @Unroll
 void "create a new customer firstName: #firstName"(){
        when: 'the merchantUser requests to create a new Customer'
        controller.request.method = 'POST'
        controller.request.contentType = JSON_CONTENT_TYPE
        controller.request.JSON = [
            firstName: firstName, lastName : lastName, middleName:middleName,
            gender: gender, email: email, phoneNumber: phoneNumber, address: address
        ]
        controller.save()

        then:'The response code should be CREATED (201)'
        controller.response.status == 201

        and: 'The new customer should be returned'
        controller.response.json.firstName == firstName
        //TODO How to validate the address is added?
        //controller.response.json.address == ????
        1 * controller.springSecurityService.getPrincipal() >> merchantUser

        where:
        firstName|lastName|middleName|gender|email|phoneNumber|address
        JSONObject.NULL     |JSONObject.NULL    |JSONObject.NULL      |JSONObject.NULL  |JSONObject.NULL |JSONObject.NULL|JSONObject.NULL
        'bob'    |'patiño'|'de'      |'M'   |'bob@patino.co'| '20055555'| [ addressLine1 :'addressLine1', postalCode:'110111',city :[name:'Bogotá',state:'DC',country:'CO']]
    }
我的控制器保存方法是

@Transactional
    def save() {
        if(handleReadOnly()) {
            return
        }
        def customer = createResource()
        customer.merchant = MerchantUser.findByUsername(springSecurityService.getPrincipal().username)?.merchant
        customer.validate()
        if (customer.hasErrors()) {
            respond customer.errors, [status: UNPROCESSABLE_ENTITY] // STATUS CODE 422
            return
        }

        customer.save()

        request.withFormat {
            json {
                respond customer, [status: CREATED] // STATUS CODE 201
            }
        }
    }
如果我调试CustomerController,我发现客户资源是通过发送信息的有效地址创建的,事实上,如果我运行代码,它可以工作,但是在运行测试时,controller.response.json不包含Address对象

我还为客户和地址设置了模拟注释

这个问题也可能与在单元测试中使用自定义封送器有关。
controller.response.json
如下所示

{
    "middleName": "de",
    "id": 1,
    "lastName": "patiño",
    "phoneNumber": "20055555",
    "merchant": {
        "id": 1,
        "class": "models.Merchant"
    },
    "email": "bob@patino.co",
    "address": {
        "id": null,
        "class": "models.Address"
    },
    "customerToken": "21jtdik0m99pnarth8g25meb423fmoh0",
    "lastUpdated": null,
    "gender": "M",
    "dateCreated": null,
    "class": "models.Customer",
    "firstName": "bob"
}

我怀疑您正在
BootStrap.groovy
中注册自定义JSON封送器,该封送器未针对某些类型的测试执行(我不清楚确切的规则,也没有很好的文档记录)


避免此限制的一种方法是使用此处描述的
ObjectMarshallerRegisterer
方法:

是的,我在Bootstrap.groovy中注册了自定义封送拆收器。我改变了你提到的文章中描述的方法,但仍然存在同样的问题。在开发或生产中运行时,它就像一个符咒,但在单元测试中,响应的地址只包含一个
{“id”:null}
我认为marshallers不起作用,因为JSON响应就像取消发送默认的JSON封送器。我相信您需要从单元切换到集成测试,以便在(模拟)控制器响应中拾取并使用JSON封送器。另外,
ObjectMarshallerRegisterer
方法的一个好处是,它极大地简化了单独测试封送器的任务(使用单元测试,而不是支付集成测试性能损失)。您是对的。在看到您的评论之前,我编写了集成测试,并且正在按它应该的方式工作。你认为这个问题仍然有效吗?我认为这个问题仍然有意义,因为我不是在测试封送员,而是在测试回复内容。是的,肯定是一个有效的问题。通常有很好的理由测试控制器响应(使用集成测试)和封送器(使用单元测试)。当您使用
ObjectMarshallerRegisterer
而不是
BootStrap.groovy
方法时,这两个级别的测试都成为可能。