Spock中final类的模拟实例在测试和开发代码中的行为不同



在我的JavaFX应用程序中,我使用Spock和Groovy进行测试。我有专门的WebBrowserController来处理我的JavafXWebView组件。我想测试一些依赖于WebView当前位置和文档的功能。

WebBrowserController的相关部分:

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

这就是我为测试创建WebBrowserController实例的方式。注意,我在那里使用的GroovyMock——普通的Mock(...)不适用于最终类,而WebEngine是最终类。

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

下面的线正在测试中,它断了。我希望返回"一些随机字符串",但我只是得到了失败的测试和NPE。

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

现在有趣的部分——我在两个地方检查了WebEngine的实例——在getMockedControllerWithDocument的末尾和上面粘贴的行。我发现它引用了同一个对象。然而,当我在测试代码之外调用任何存根方法时,我被NPE击中了——getLocation()执行了实际的实现,而不是存根(原始方法不仅仅是一个简单的getter,它在两者之间使用了一个包装值)。

总结一下:为什么完全相同的对象的行为会因其方法被调用的位置而异?

因为GroovyMockGroovySpyGroovyStub只能按照Groovy类的预期工作。当Java类调用时,它们的行为就像普通的Spock mock。这里记录了这一点:

TIP

Groovy Mock什么时候应该比常规Mock更受欢迎?当规范下的代码是用Groovy编写的,并且需要一些独特的Groovy mock功能时,应该使用Groovy mock当从Java代码调用时,Groovy mock的行为将类似于常规mock注意,不必仅仅因为规范和/或mock类型下的代码是用Groovy编写的,就使用Groovy mock。除非您有具体的理由使用Groovy mock,否则最好使用常规的mock。

最新更新