Spock предоставляет 3 мощных (но разных по сути) инструмента, упрощающих написание тестов: Mock, Stub и Spy. Довольно часто коду, который нужно протестировать, требуется взаимодействовать с внешними модулями, называющимися зависимостями (в оригинальной статье используется термин collaborators, который не очень распространён в русскоязычной среде). Модульные тесты чаще всего разрабатываются для тестирования одного изолированного класса при помощи различных вариантов моков: Mock, Stub и Spy. Так тесты будут надёжнее и будут реже ломаться по мере того, как код зависимостей эволюционирует. Такие изолированные тесты менее подвержены проблемам при изменении внутренних деталей реализации зависимостей. От переводчика: каждый раз, когда я использую Spock Framework для написания тестов, я чувствую, что могу ошибиться при выборе способа подмены зависимостей. В этой статье есть максимально краткая шпаргалка по выбору механизма для создания моков. Используйте Mock для: Используйте Stub для: Бойтесь шпионов (Spy). Как сказано в документации Spock: Но так уж случается, что бывают ситуации, когда мы должны работать с легаси кодом. Легаси код бывает сложно или даже невозможно протестировать при помощи моков и стабов. В этом случае есть всего один вариант решения — использовать Spy. Лучше иметь легаси код, покрытый тестами с использованием Spy, чем не иметь тестов для легаси совсем. Используйте Spy для: Вся сила моков проявляется, когда задача модульного теста состоит в проверке контракта между тестируемым кодом и зависимостями. Давайте посмотрим на следующий пример, где у нас имеется контроллер FooController, который использует FooService в качестве зависимости, и протестируем эту функциональность при помощи моков. FooController.groovy FooService.groovy В этом сценарии мы хотим написать тест, который проверит: Взглянем на тест: MockSpec.groovy Приведённый тест создаёт мок сервиса: Также тест проверяет, что FooService.doSomething(name) вызывается один раз, и параметр, переданный в него, совпадает со строкой "Sally". Приведённый код решает 4 важные задачи: Использует ли тестируемый код зависимости? Является ли целью тестирования удостовериться, что тестируемый код работает корректно при взаимодействии с зависимостями? Являются ли результаты вызовов методов зависимостей входными значениями для тестируемого кода? Если поведение тестируемого кода изменяется в зависимости от поведения зависимостей, то вам необходимо использовать стабы (Stub). Давайте посмотрим на следующий пример с FooController и FooService и протестируем функциональность контроллера при помощи стабов. FooController.groovy FooService.groovy Код теста: StubSpec.groovy Создать стаб можно так: Приведённый код решает 4 важные задачи: Пожалуйста не читайте этот раздел. Не смотрите. Пропускайте и переходите к следующему. Всё ещё читаете? Ну что ж, хорошо, давайте разбираться со Spy. Не используйте Spy. Как сказано в документации Spock: При этом бывают ситуации, когда нам приходится работать с легаси кодом. Легаси код бывает невозможно протестировать с помощью моков или стабов. В этом случае шпион остаётся единственным жизнеспособным вариантом. Шпионы отличаются от моков или стабов, потому что они работают не как заглушки. Когда зависимость подменяется моком или стабом, создается тестовый объект, а настоящий исходный код зависимости не выполняется. Шпион, с другой стороны, выполнит основной исходный код зависимости, для которой был создан шпион, но шпион позволит вам изменять то, что возвращает шпион, и проверять вызовы методов, так же как моки и стабы. (Отсюда и название Spy). Давайте посмотрим на следующий пример FooController, который использует FooService, а затем протестируем функциональность с помощью шпиона. FooController.groovy FooService.groovy Код теста: SpySpec.groovy Создать экземпляр-шпион довольно просто: В приведённом коде шпион позволяет нам проверить вызов FooService.doSomething(name), количество вызовов и значения параметров. Более того, шпион изменяет реализацию метода, чтобы вернуть другое значение. Приведённый код решает 4 важные задачи: Какой из вариантов использовать: Mock, Stub или Spy? Это вопрос, с которым сталкиваются многие разработчики. Этот FAQ может помочь, если вы не уверены, какой из подходов использовать. Q: Является ли целью тестирования проверка контракта между тестируемым кодом и зависимостями? A: Если вы ответили Да, используйте Mock Q: Является ли целью тестирования удостовериться, что тестируемый код работает верно при взаимодействии с зависимостями? A: Если вы ответили Да, используйте Stub Q: Являются ли результаты вызовов методов зависимостей входными значениями для тестируемого кода? A: Если вы ответили Да, используйте Stub Q: Работаете ли вы с легаси кодом, который очень сложно протестировать, и у вас не осталось вариантов? A: Попробуйте использовать Spy Вы можете найти код всех примеров этой статьи по ссылке: https://github.com/ddelponte/mock-stub-spy