Тест на основе взаимодействия Спока: слишком мало вызовов метода

У меня есть метод ниже, который довольно прост. Он вызывает другой метод, который мягко удаляет ключ API, а затем вызывает другой метод для создания нового и возвращает его.

Ниже приведен тест, который просто проверяет, что оба метода были вызваны правильно. Но все равно получаю 0 ошибка вызова на обоих методах. Что вызывает эту проблему?

AuthApiKeyPair updateApiKeyPair(AuthApiKeyPair apiKeyPair, Boolean createNewKey) {

    AuthApiKeyPair newKeyPair

    if (createNewKey) {
        deleteApiKeyPair(apiKeyPair)

        //The key will be created with the same info as the previous key.
        newKeyPair = createApiKeyPair(apiKeyPair.label, apiKeyPair.accountMode, apiKeyPair.source)
    }

    newKeyPair
}

ТЕСТОВОЕ ЗАДАНИЕ:

def "should soft delete key pair and create new one"() {
    setup:
    AuthApiKeyPair apiKeyPair = AuthApiKeyPair.build(acquirerId: 123, source: PaymentSource.BOARDING_API, label: 'Boarding API key')

    when:
    service.updateApiKeyPair(apiKeyPair, true)

    then:
    1 * service.deleteApiKeyPair(apiKeyPair)
    1 * service.createApiKeyPair(apiKeyPair.label, apiKeyPair.accountMode, apiKeyPair.source)
}

1 ответ

Решение

Если вы подумаете о своем тесте, вы поймете, что в лучшем случае он проверяет механизм спока, а не ваш бизнес-код. Вы не показали нам полный класс со своей спецификацией теста, однако, исходя из вашего сценария, мы можем предположить, что service в твоем тесте это просто издевательство. Если это правда, то вы не можете ожидать этих двух вызовов:

then:
1 * service.deleteApiKeyPair(apiKeyPair)
1 * service.createApiKeyPair(apiKeyPair.label, apiKeyPair.accountMode, apiKeyPair.source)

произойдет. Просто потому, что смоделированный класс не выполняет реальные методы.

Я настоятельно рекомендую вам протестировать реальный класс, а не то, какие вызовы вызывает конкретный метод, а каковы ожидаемые (и детерминированные) результаты вызова конкретного метода (ов). Вы могли бы выполнить service.updateApiKeyPair(apiKeyPair, true) на реальном объекте в when и затем вы можете проверить, была ли создана новая пара ключей API (и сохранена ли она в хранилище, которое вы используете) и не существует ли старая пара больше. Такой тест имеет как минимум несколько преимуществ по сравнению только с проверкой вызовов:

  • Вы можете изменить реализацию service.updateApiKeyPair() в любое время и до тех пор, пока он дает те же результаты, ваш тест все еще полезен (потому что тест не ограничивает вашу реализацию, как тест вызова),
  • вы проверяете реальное поведение, а не насмешливую библиотеку - есть анекдот, в котором говорится, что Mockito - самая проверенная библиотека в миллионах проектов.

Конечно, это может потребовать некоторых изменений дизайна. Я предполагаю, что в вашем классе обслуживания используется какой-то внедренный DAO или репозиторий, в котором хранятся пары ключей API. Подумайте о предоставлении реализации DAO в памяти для вашего теста - класса, который вместо сохранения объектов в реальной базе данных хранит все объекты во внутренней памяти. ConcurrentMap<K,V>, Благодаря этому вы все еще можете запустить свой тест как модульный тест и проверить, обновляется ли пара ключей API с createNewKey параметр установлен в true делает именно то, что вы ожидаете. В качестве альтернативы вы могли бы написать интеграционный тест с заменой базы данных H2, но это только увеличит длительность начальной загрузки теста. Выбор за вами.

Есть одно правило, которое стоит запомнить - если ваш класс / компонент / функциональность и т. Д. Сложно тестировать модулем, это означает, что был сделан неправильный выбор дизайна.

Альтернатива: Спок Spy объекты

Есть одна вещь, которую я упоминаю в конце специально. Спок поддерживает так называемые "шпионские" объекты, которые ведут себя как реальные объекты, но они позволяют вам заглушить некоторые части и рассматривать этот объект как насмешку, например, для подсчета вызовов. Но даже авторы Spock предупреждают разработчиков об использовании этой функции:

(Подумайте дважды, прежде чем использовать эту функцию. Может быть, лучше изменить дизайн кода в спецификации.)

Источник: http://spockframework.org/spock/docs/1.0/interaction_based_testing.html

Я не знаю, есть ли у Grails аннотации для теста для создания Spy вместо Mock, но вы всегда можете следовать официальной документации и создать простой модульный тест Spock, который создает ваш сервис как Spy, а затем вы можете попробовать подсчитать количество вызовов. Я бы не советовал делать это, просто упомянув об этом для записи.

Другие вопросы по тегам