Если зависимости в ваш код внедряются через конструктор или через сеттеры, использование EasyMock очевидно: создаём mock и передаём его в тестируемый object. А если зависимости внедряются напрямую в поля класса, EasyMock связывает их автоматически 🙂
Возьмём код примера Hello, EasyMock и добавим к нему пару классов:
1 2 3 4 5 6 7 8 9 10 11 | public interface ServiceInterface { String doSomething(); } public class Consumer { private ServiceInterface serviceInterface; public String opinion() { return "Service was: " + serviceInterface.doSomething(); } } |
Протестируем класс Consumer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class ConsumerTest { @Rule public EasyMockRule em = new EasyMockRule(this); @TestSubject Consumer testedObject = new Consumer(); @Mock ServiceInterface service; @Test public void testOpinion() { expect(service.doSomething()).andStubReturn("for testing purposes only"); replay(service); assertThat(testedObject.opinion(), is("Service was: for testing purposes only")); } } |
EasyMockRule особым образом обрабатывает поля тестового класса, аннотированные @Mock и @TestSubject.
Для каждого поля с аннотацией @Mock создаётся mock объект, имеющий поведение по умолчанию (nice mock). Состояние и поведение этого mock’а будет автоматически сбрасываться к исходному перед запуском каждого теста.
После создания mock’а он будет автоматически внедрён во все совместимые по типу поля объекта, помеченного @TestSubject, последний, кстати, надо создавать вручную. Таким образом связывание зависимостей производится автоматически и без оглядки на какие-либо dependency injection фреймворки.
Отмечу, что связывание в EasyMock жадное: найдя одно совместимое по типу поле EasyMock не остановится на нём и продолжит искать следующие подходящие поля и подсовывать в них mock объекты:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class MultiConsumer { private ServiceInterface firstService; private ServiceInterface secondService; public String opinion() { return "Service was: " + firstService.doSomething() + " and " + secondService.doSomething(); } } public class MultiConsumerTest { @Rule public EasyMockRule em = new EasyMockRule(this); @TestSubject MultiConsumer testedObject = new MultiConsumer(); @Mock ServiceInterface service; @Test public void testOpinion() { expect(service.doSomething()).andStubReturn("great"); replay(service); assertThat(testedObject.opinion(), is("Service was: great and great")); } } |
В случае, если необходимо использовать разные mock’и одного (или совместимого) типа, можно явно указать имя поля, для которого этот mock предназначен:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class TwoMocksTest { @Rule public EasyMockRule em = new EasyMockRule(this); @TestSubject MultiConsumer testedObject = new MultiConsumer(); @Mock(fieldName = "firstService") ServiceInterface firstService; @Mock(fieldName = "secondService") ServiceInterface secondService; @Test public void testOpinion() { expect(firstService.doSomething()).andStubReturn("great"); expect(secondService.doSomething()).andStubReturn("superior"); replay(firstService); replay(secondService); assertThat(testedObject.opinion(), is("Service was: great and superior")); } } |
Код примера доступен на github.