Mocked instance of final class in Spock behaves differently in test and dev code

匆匆过客 提交于 2020-06-09 04:12:53

问题


In my JavaFX application I am using Spock and Groovy for testing. I have dedicated WebBrowserController for taking care of my JavafX WebView component. I wanted to test some functionalities that depend on current Location and Document of the WebView.

Relevant part of WebBrowserController:

public WebEngine getEngine() {
    return panel.getWebView().getEngine();
}

This is how I create an instance of WebBrowserController for my tests. Notice the GroovyMock I used there - ordinary Mock(...) does not work for final classes and WebEngine is a final class.

WebBrowserController getMockedControllerWithDocument(Document document) {
    WebBrowserController controller = Mock(WebBrowserController)
    controller.getEngine() >> GroovyMock(WebEngine) {
        getDocument() >> document
        getLocation() >> "some random string"
    }

    controller
}

The line below is under the test and it breaks. I would expect "some random string" to be returned but I just get failed test and NPE.

String url = controller.get().getEngine().getLocation()

Now the interesting part - I have examined the instance of WebEngine in two places - at the end of getMockedControllerWithDocument and at the line pasted above. What I found out is that it referenced the same object. Yet, when I invoked any of the stubbed methods outside of test code I was hit by NPE - getLocation() executed the actual implementation and not the stub (the original method is not just a simple getter and it uses a wrapped value in between).

Summing it up: why the hell does the exact same object behaves differently depending on the place its methods are being invoked?


回答1:


Because GroovyMock, GroovySpy and GroovyStub only work as you expect for Groovy classes. When called by Java classes, they behave like normal Spock mocks. This is documented here:

TIP

When Should Groovy Mocks be Favored over Regular Mocks? Groovy mocks should be used when the code under specification is written in Groovy and some of the unique Groovy mock features are needed. When called from Java code, Groovy mocks will behave like regular mocks. Note that it isn’t necessary to use a Groovy mock merely because the code under specification and/or mocked type is written in Groovy. Unless you have a concrete reason to use a Groovy mock, prefer a regular mock.



来源:https://stackoverflow.com/questions/54180395/mocked-instance-of-final-class-in-spock-behaves-differently-in-test-and-dev-code

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