4

I'm trying to write some integration tests for a RestfulController in Grails 2.4.0 responding in JSON format. The index()-Method is implemented like this:

class PersonController extends RestfulController<Person> {
    ...
    def index(final Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond listAllResources(params), [includes: includeFields]
    }
    ...
}

The integration test looks like this:

void testListAllPersons() {
    def controller = new PersonController()
    new Person(name: "Person", age: 22).save(flush:true)
    new Person(name: "AnotherPerson", age: 31).save(flush:true)

    controller.response.format = 'json'
    controller.request.method = 'GET'

    controller.index()

    assertEquals '{{"name":"Person", "age": "22"},{"name":"AnotherPerson", "age": "31"}}', controller.response.json
}

What i don't understand is controller.response.json only contains the "AnotherPerson" instead of both entries. When i start the server with run-app und test it with a Rest-Client i get both entries. Any Ideas?

marco
  • 43
  • 1
  • 4
  • response should be a `JSONArray`. You are asserting it to an invalid `JSONObject`. Can you also show the assertion failure message. – dmahapatro May 28 '14 at 17:18

2 Answers2

5

You haven't included enough information to say for sure what the problem is but the following test passes with 2.4.0.

The domain class:

// grails-app/domain/com/demo/Person.groovy
package com.demo

class Person {
    String name
    Integer age
}

The controller:

// grails-app/controllers/com/demo/PersonController.groovy
package com.demo

class PersonController extends grails.rest.RestfulController<Person> {

    PersonController() {
        super(Person)
    }

    def index(final Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond listAllResources(params)
    }
}

The test:

// test/unit/com/demo/PersonControllerSpec.groovy
package com.demo

import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(PersonController)
@Mock(Person)
class PersonControllerSpec extends Specification {


    void "test index includes all people"() {
        given:
        new Person(name: "Person", age: 22).save(flush:true)
        new Person(name: "AnotherPerson", age: 31).save(flush:true)

        when:
        request.method = 'GET'
        response.format = 'json'
        controller.index()

        then:
        response.status == 200
        response.contentAsString == '[{"class":"com.demo.Person","id":1,"age":22,"name":"Person"},{"class":"com.demo.Person","id":2,"age":31,"name":"AnotherPerson"}]'
    }
}
Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
  • Did you have to override index in the personController? The implementation you provided is very similar to the one in RestfulController.respond listAllResources(params), model: [("${resourceName}Count".toString()): countResources()] You are just missing the resource count. – burns May 04 '15 at 15:22
  • "Did you have to override index in the personController?" - I don't think I understand the question. The index action is defined in the PersonController that I showed above. – Jeff Scott Brown May 04 '15 at 17:42
  • Your PersonController class above extends grails.rest.RestfulController. There is a default implementation for the index action in that class. – burns May 05 '15 at 03:52
  • I think your answer is 100% correct. The unit test will fail without implementing the index method in the PersonController. I've been playing around with some similar code, and the RestfulController superclass returns an empty list of domain objects when unit testing. But when the application is running, the full list is returned. It just seems a bit odd that you would need to implement the index method in the subclass to get the unit test to work. – burns May 05 '15 at 04:01
  • I asked a new question here http://stackoverflow.com/questions/30044903/odd-behavior-with-default-index-action-when-unit-testing-a-restfulcontroller-in that demonstrates the issue with having to override index in the controller. – burns May 05 '15 at 05:30
0

I simplified the example a little too much. I used a named object marshaller which i created (incorrect) in bootstrap.groovy like this:

   JSON.createNamedConfig('simplePerson') { converterConfig ->
        converterConfig.registerObjectMarshaller(Person) {
            JSON.registerObjectMarshaller(Person) {
                def map = [:]
                map['name']  = it.name
                map['age']  = it.age
                return map
            }
        }
    }

And used it in the controller:

...
JSON.use("simplePerson")
...

The problem is solved by creating the object marshaller like this:

    JSON.createNamedConfig('simplePerson') { converterConfig ->
        converterConfig.registerObjectMarshaller(Person) {
            def map = [:]
            map['name']  = it.name
            map['age']  = it.age
            return map                
        }
    }
marco
  • 43
  • 1
  • 4