EasyMock mocks: nice, default, strict, stub и partial

В ознакомительном примере EasyMock, я писал: «в аннотации @Mock я указал, что хочу так называемый “nice mock”. На самом деле, аннотация @Mock(type = MockType.NICE) создает full nice non-strict mock, что означает «mock с подменой всех методов, поведением по умолчанию и без проверки порядка вызовов». Какие ещё есть варианты mock’ов?

Поскольку рассуждать мы будет в основном о поведении разных видов mock-объектов, весь код будет содержаться в самой статье, без отдельного примера.

Nice/Default/Strict

В аннотацию @Mock передаётся параметр type, который может принимать три значения:

  • MockType.NICE
  • MockType.DEFAULT
  • MockType.STRICT

Причем значение по умолчанию… MockType.DEFAULT которое создаёт mock требующий явного задания поведения через вызов expect() и если вызвать метод, для которого поведение не задано, выбросит AssertionError  и провалит тест.

В отличие от default типа, mock с MockType.NICE создаёт mock с поведением по умолчанию: для каждого не private и не final метода класса будет возвращено значение по умолчанию, если поведение метода не задано:

  • 0 для числовых типов
  • false для Boolean типа
  • null для всех остальных типов.
MockType.Strict ещё больше закручивает гайки — для mock’а этого типа не только обязательно надо задавать поведение методов явно, но и именно в том порядке, в котором их будет проверять тестируемый код:

Partial Mock

Аннотация @Mock создаёт full mock объект, у которого все не final и не private методы заменены на методы, сгенерированные EasyMock. Однако иногда требуется заменить только некоторые методы, например когда тестируемый класс вызывает сам себя и мы тестируем вызывающий код. В этом случае можно вручную создать частичный (partial) mock:

Надо отметить, что в partial mock стандартные методы класса Object, такие как equals(), hashCode(), toString(), finalize() не будут заменены, если их явно не указать в addMockedMethod(). Это отличается от поведения full mock, у которого эти методы так же заменяются на EasyMock реализации.

Stub mocks

Stub mock это не совсем разновидность mock’а, это вариант его использования. Выше, говоря про strict mock’и я говорил, что для этого типа mock-объектов проверяется порядок вызовов, то есть поведение. Для default mock’ов поведение тоже проверятся: количество вызовов, обязательность вызовов, параметры итд. Но, если вы тестируете результат выполнения, а не поведение, то все эти возможности только мешают.

Например у вас есть зависимость, у которой можно спросить текущего пользователя.  Некоторые методы тестируемого класса вызывают этот метод, некоторые не вызывают, а некоторые вызывают дважды. Описывать это поведение для каждого теста не только неудобно, но и вызывает дополнительную работу при рефакторинге. При том, что поведение этого метода нам вообщем-то неинтересно вовсе.

Решение этой проблемы в замене результата вызова expect():

andStubReturn() говорит EasyMock, что мы не беспокоимся о том, когда вызван этот метод, сколько раз он вызван или вызыван ли вообще.

Stub методы можно использовать и с исключениями и с динамически генерируемыми ответами. В одном mock объекте можно смешивать и stub и поведенческие методы. А тестированию поведения будет посвящена отдельная статья.