Если зависимости в ваш код внедряются через конструктор или через сеттеры, использование 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.