Если вы подумаете о своем тесте, вы поймете, что в лучшем случае он проверяет механизм спока, а не ваш бизнес-код. Вы не показали нам полный класс со своей спецификацией теста, однако, исходя из вашего сценария, мы можем предположить, что 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#spies
Я не знаю, есть ли у Grails аннотации для теста для создания шпиона вместо макета, но вы всегда можете следовать официальной документации и создать простой модульный тест Спока, который создает ваш сервис как шпион и тогда вы можете попробовать подсчитать количество вызовов. Я бы не советовал делать это, просто упомянув об этом для записи.