Модулированный экземпляр final класса в Spock ведет себя по-разному в тестовом и dev-коде - PullRequest
0 голосов
/ 14 января 2019

В моем приложении JavaFX я использую Spock и Groovy для тестирования. Я выделил WebBrowserController для заботы о моем компоненте JavafX WebView. Я хотел протестировать некоторые функции, которые зависят от текущего местоположения и документа 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() выполнил фактическую реализацию, а не заглушку (оригинальный метод - не просто простой метод получения, и он использует промежуточное значение между ними) .

Подводя итог: почему, черт возьми, один и тот же объект ведет себя по-разному в зависимости от того, где вызываются его методы?

1 Ответ

0 голосов
/ 14 января 2019

Поскольку GroovyMock, GroovySpy и GroovyStub работают только так, как вы ожидаете для классов Groovy. При вызове Java-классами они ведут себя как обычные макеты Спока. Это задокументировано здесь :

TIP

Когда следует использовать Groovy Mock вместо обычных Mock? Groovy mock следует использовать, когда специфицированный код написан на Groovy, и необходимы некоторые уникальные функции Groovy. При вызове из кода Java Groovy mock будет вести себя как обычные mock. Обратите внимание, что нет необходимости использовать Groovy mock только потому, что код по спецификации и / или mocked-типу написано в Groovy. Если у вас нет конкретной причины использовать макет Groovy, предпочитайте обычный макет.

...