How can I mock a grails 4 service in a controller unit test

ぐ巨炮叔叔 提交于 2020-01-05 08:27:11

问题


I don't understand how mocking works in Grails 4.0. I have this unit test that fails (it is just an illustration of the real test, the real test actually involves the controller):

import com.myapp.MySearchService

class ApiControllerSpec extends Specification implements ControllerUnitTest<ApiController> {

    def setup() {
    }

    def cleanup() {
    }

    void "test listSources"() {
        given:
        def mock = Mock(MySearchService) {
            find(_) >> [["label": "abc", "description": "xsad"]]
        }

        when:
        System.out.println(mock.find(''))

        then:
        1 * mock.find(_) >> [["label": "abc", "description": "xsad"]]
    }

with error

Too few invocations for:

1 * mock.find(_) >> [["label": "abc", "description": "xsad"]]   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * mock.invokeMethod('find', [<java.lang.String@0 value= hash=0>])


    at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:93)
    at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:77)
    at toe.ApiControllerSpec.test listSources(ApiControllerSpec.groovy:29)

and stdout

null

The interesting thing is that this works fine if I use a very simple test class instead of MySearchService. So I am assuming that it has to do something with the way Grails/Spring is setup. This might also explain the lines:

Unmatched invocations (ordered by similarity):

1 * mock.invokeMethod('find', [<java.lang.String@0 value= hash=0>])

But how do I set it up otherwise? I can't find this anywhere in the documentation. Thanks for any help!

Similar question (without answer): How to partially mock service in Grails integration test


回答1:


The syntax for your mock is incorrect - here's a working example tested in Grails 4.0.1

    void "test something"() {
        given:
        def mock = Mock(SearchService) {
            1 * find(_) >> ['foobar'] // note the interaction count is required when defining this way.
        }

        when:
        def result = mock.find('')

        then:
        result == ['foobar']
    }

See - http://spockframework.org/spock/docs/1.0/interaction_based_testing.html - Section: Declaring Interactions at Mock Creation Time

Note this is likely not in the Grails docs as there is nothing Grails specific about it - just Spock.




回答2:


here is already a workaround that is not great:

    void "test listSources"() {
        given:
        def mock = Mock(MySearchService) {
            invokeMethod('find', _) >> [["label": "abc", "description": "xsad"]]
        }

        when:
        System.out.println(mock.find(''))

        then:
        1 * mock.invokeMethod('find', _) >> [["label": "abc", "description": "xsad"]]
    }


来源:https://stackoverflow.com/questions/59030447/how-can-i-mock-a-grails-4-service-in-a-controller-unit-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!