问题
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