Search code examples
unit-testinggrailsspockgrails-4

Grails 4.0 Mock service method in controller test


I have a controller like this:

class NotificationApiController {

    def countService

    def getCount() {
        def results = countService.getCount()

        render results as JSON
    }
}

And the controller test like this:

Closure doWithSpring() {{ ->
        countService(CountService)
    }}

CountService countService

def setup() {
}

def cleanup() {
}

void "test getCount method"() {
        given:
        def countService = Mock(CountService) {
            1 * getCount(_) >> [count: 2]
        }
        when:
        def y = controller.getCount()

        then:
        y == [count: 2]
    }

It appears it always calls into the actual CountService injected in Closure doWithSpring(), not my mock countService, but without the definition of Closure doWithSpring()..., I will get this error

Cannot invoke method getCount() on null object
java.lang.NullPointerException: Cannot invoke method getCount() on null object

The documentation on unit testing in 4.0 is really limited and I am not exactly sure how should I do this. I see some samples in Grails 2.3 or 3.3. version, but they all seems not working for me, mostly due to the difference of Spock and Mixin framework I guess. Any suggestions on how to do this?


Solution

  • You have omitted some details that might affect the recommendation but the project at https://github.com/jeffbrown/chrisjiunittest shows 1 way to go about this.

    https://github.com/jeffbrown/chrisjiunittest/blob/a59a58e3b6ed6b47e1a8104f3e4d3bdb138abacc/src/test/groovy/chrisjiunittest/NotificationApiControllerSpec.groovy

    package chrisjiunittest
    
    import grails.testing.web.controllers.ControllerUnitTest
    import spock.lang.Specification
    
    class NotificationApiControllerSpec extends Specification implements ControllerUnitTest<NotificationApiController> {
    
        void "test something"() {
            setup:
            // whether or not this is the right thing to do
            // depends on some other factors, but this is
            // an example of one approach...
            controller.countService = Mock(CountService) {
                getCount() >> [count: 2]
            }
    
            when:
            controller.getCount()
    
            then:
            response.json == [count: 2]
        }
    }
    

    Another option:

    package chrisjiunittest
    
    import grails.testing.web.controllers.ControllerUnitTest
    import spock.lang.Specification
    
    class NotificationApiControllerSpec extends Specification implements ControllerUnitTest<NotificationApiController> {
    
        Closure doWithSpring() {
            // whether or not this is the right thing to do
            // depends on some other factors, but this is
            // an example of one approach...
            { ->
                countService MockCountService
            }
        }
    
        void "test something"() {
            when:
            controller.getCount()
    
            then:
            response.json == [count: 2]
        }
    }
    
    class MockCountService {
        Map getCount() {
            [count: 2]
        }
    }