Я не буду спорить о читаемости, размерах или методах тестирования этих фреймворков, Я считаю, что они равны, но на простом примере я покажу вам разницу.
Дано: У нас есть класс, который отвечает за сохранение чего-то где-то:
public class Service {
public static final String PATH = "path";
public static final String NAME = "name";
public static final String CONTENT = "content";
private FileDao dao;
public void doSomething() {
dao.store(PATH, NAME, IOUtils.toInputStream(CONTENT));
}
public void setDao(FileDao dao) {
this.dao = dao;
}
}
, и мы хотим, чтобы проверить:
Mockito:
public class ServiceMockitoTest {
private Service service;
@Mock
private FileDao dao;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
// when
service.doSomething();
// then
ArgumentCaptor<InputStream> captor = ArgumentCaptor.forClass(InputStream.class);
Mockito.verify(dao, times(1)).store(eq(Service.PATH), eq(Service.NAME), captor.capture());
assertThat(Service.CONTENT, is(IOUtils.toString(captor.getValue())));
}
}
EasyMock:
public class ServiceEasyMockTest {
private Service service;
private FileDao dao;
@Before
public void setUp() {
dao = EasyMock.createNiceMock(FileDao.class);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
Capture<InputStream> captured = new Capture<InputStream>();
dao.store(eq(Service.PATH), eq(Service.NAME), capture(captured));
replay(dao);
// when
service.doSomething();
// then
assertThat(Service.CONTENT, is(IOUtils.toString(captured.getValue())));
verify(dao);
}
}
Как вы можете видеть, оба теста довольно одинаковы, и оба они проходят. Теперь давайте представим, что кто-то другой изменил реализацию службы и попытался запустить тесты.
реализация
Новая услуга:
dao.store(PATH + separator, NAME, IOUtils.toInputStream(CONTENT));
сепаратор был добавлен в конце PATH постоянной
Как тесты результаты будут выглядеть, как сейчас? Прежде всего, оба теста не получится, но с различными сообщениями об ошибках:
EasyMock:
java.lang.AssertionError: Nothing captured yet
at org.easymock.Capture.getValue(Capture.java:78)
at ServiceEasyMockTest.testDoSomething(ServiceEasyMockTest.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
Mockito:
Argument(s) are different! Wanted:
dao.store(
"path",
"name",
<Capturing argument>
);
-> at ServiceMockitoTest.testDoSomething(ServiceMockitoTest.java:34)
Actual invocation has different arguments:
dao.store(
"path\",
"name",
[email protected]
);
-> at Service.doSomething(Service.java:13)
То, что произошло в тесте EasyMock, почему результат не был захвачен? Метод магазина не был выполнен, но подождать минуту, это было, почему EasyMock лежит на нас?
Это потому, что EasyMock смешивает две обязанности в одной строке - ступень и проверка. Вот почему, когда что-то не так, трудно понять, какая часть вызывает провал.
Конечно, вы можете сказать мне - просто измените тест и переместите проверку перед утверждением. Вау, ты серьезно, разработчики должны помнить о каком-то волшебном порядке, освещенном насмешливыми фреймами?
Кстати, это не поможет:
java.lang.AssertionError:
Expectation failure on verify:
store("path", "name", capture(Nothing captured yet)): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:111)
at org.easymock.classextension.EasyMock.verify(EasyMock.java:211)
Тем не менее, он говорит мне, что метод не был казнен, но это было, только с другими параметрами.
Почему Mockito лучше? Эта структура не смешивает две обязанности в одном месте, и когда ваши тесты потерпят неудачу, вы легко поймете, почему.
Да, я думал то же самое: с Mockito (и Unitils Мок, подобный насмешливый API) гораздо проще писать тесты, которые продолжают счастливо пройти, когда они не должны. Я подозреваю, что это может быть основной причиной того, что Mockito-подобные API, которые упрощают создание чрезмерно «рыхлых» тестов, часто считаются «более легкими». –
Мне было бы интересно увидеть пример, который контрастирует с этими двумя подходами ... – Armand