2010-05-19 5 views
41

Один из способов думать об этом: если мы заботимся о дизайне кода, то EasyMock - лучший выбор, поскольку он дает вам обратную связь по его концепции ожиданий.EasyMock vs Mockito: дизайн и ремонтопригодность?

Если мы заботимся об ремонтопригодности тестов (легче читать, писать и иметь менее хрупкие тесты, которые не сильно зависят от изменения), то Mockito кажется лучшим выбором.

Мои вопросы:

  • Если вы использовали EasyMock в крупных проектах, вы обнаружите, что ваши тесты труднее поддерживать?
  • Каковы ограничения Mockito (кроме эндо-тестирования)?

ответ

26

Я разработчик EasyMock, поэтому немного частичный, но, конечно, я использовал EasyMock для крупномасштабных проектов.

Мое мнение таково, что тесты EasyMock действительно будут ломаться время от времени. EasyMock заставляет вас делать полную запись того, что вы ожидаете. Это требует определенной дисциплины. Вы должны действительно записать то, что ожидается не то, что в настоящее время требуется испытанному методу. Например, если неважно, сколько раз метод вызывается на макет, не бойтесь использовать andStubReturn. Кроме того, если вам не нужен параметр, используйте anyObject() и так далее. Мышление в TDD может помочь в этом.

Мой анализ заключается в том, что тесты EasyMock будут ломаться чаще, но Mockito не будет, когда вы захотите их. Я предпочитаю, чтобы мои тесты ломались. По крайней мере, я знаю, каковы были последствия моего развития. Это, конечно, моя личная точка зрения.

+1

Да, я думал то же самое: с Mockito (и Unitils Мок, подобный насмешливый API) гораздо проще писать тесты, которые продолжают счастливо пройти, когда они не должны. Я подозреваю, что это может быть основной причиной того, что Mockito-подобные API, которые упрощают создание чрезмерно «рыхлых» тестов, часто считаются «более легкими». –

+3

Мне было бы интересно увидеть пример, который контрастирует с этими двумя подходами ... – Armand

7

Я не думаю, что вы должны быть слишком обеспокоены этим. Оба Easymock и Mockito могут быть настроены так, чтобы быть «строгими» или «хорошими», единственное отличие состоит в том, что по умолчанию Easymock является строгим, поскольку Mockito - это хорошо.

Как и во всех тестах, нет жесткого и быстрого правила, вам необходимо сбалансировать уверенность теста в отношении ремонтопригодности. Я обычно нахожу, что есть определенные функциональные или технические области, которые требуют высокого уровня уверенности, для которого я бы использовал «строгие» издевательства. Например, мы, вероятно, не хотели бы, чтобы метод debitAccount() вызывался более одного раза! Однако есть и другие случаи, когда макет действительно немного больше, чем заглушка, поэтому мы можем проверить реальное «мясо» кода.

В первые дни жизни Mockito совместимость с API была проблемой, но теперь больше инструментов поддерживают фреймворк. Powermock (личный фаворит) теперь имеет расширение Mockito

42

, если мы заботимся о дизайне кода, то EasyMock является лучшим выбором, поскольку это дает обратную связь с вами по своей концепции ожидания

Интересное , Я обнаружил, что «концепция ожиданий» заставляет многих разработчиков добавлять больше ожиданий в тесты только для удовлетворения проблемы UnexpectedMethodCall. Как это влияет на дизайн?

Тест не должен прерываться при изменении кода. Тест прекращается, когда функция перестает работать.Если кому-то нравится, когда тесты прерываются, когда происходит какое-либо изменение кода, я предлагаю написать тест, который утверждает контрольную сумму md5 java-файла :)

94

Я не буду спорить о читаемости, размерах или методах тестирования этих фреймворков, Я считаю, что они равны, но на простом примере я покажу вам разницу.

Дано: У нас есть класс, который отвечает за сохранение чего-то где-то:

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 лучше? Эта структура не смешивает две обязанности в одном месте, и когда ваши тесты потерпят неудачу, вы легко поймете, почему.

+0

Я продаюсь сначала при попытке mockito. Проверка работоспособности достаточно грязная, а макетные рамки мешают. – Gary

+0

Я понимаю, что это старый ... но, это вы смешиваете процессы проверки и stubbing здесь не EasyMock. Неправильная практика делать утверждения перед проверкой - таким образом, вы можете фактически удалить вызов «assertThat», потому что проверка подберет его для вас: «FileStore.dao (« путь »,« имя »,« захват »(« Nothing Captured yet »): ожидаемый 1, фактический: 0 ". Я соглашусь, что сообщение Mockito здесь яснее, но этого недостаточно, чтобы повлиять на чье-то решение о EasyMock! –

+0

Я не уверен, как я тут что-то смешал для EasyMock, так это, как это работает, поэтому, если у вас есть хороший встречный пример, я был бы рад увидеть его. Я думаю, что это вопрос личного мнения, или нет, этот пример достаточно хорош, чтобы влиять на решение этих структур, и я рад, что многие люди считают это ценным. –

5

Я предпочитаю mockito, если быть честным. использует EasyMock с унилидами, и комбинация часто приводит к исключениям, таким как IllegalArgumentException: не интерфейс, а также MissingBehaviorExceptions. В обоих случаях код и тестовый код в порядке. Оказалось, что исключение MissingBehaviorException было связано с тем, что издевавшиеся объекты, созданные с помощью createMock (используя classextentions !!), действительно вызвали эту ошибку. При использовании @Mock это действительно сработало!Мне не нравится такое вводящее в заблуждение поведение, и для меня это явное указание, что разработчики этого не знают, что делают. Хорошая структура всегда должна быть простой в использовании, а не двусмысленной. Исключение IllegalArgumentException также было связано с некоторыми смешениями внутренних компонентов EasyMock. Кроме того, запись не является тем, что я хочу сделать. Я хочу проверить, не генерирует ли мой код исключения или нет, и что он возвращает ожидаемые результаты. Это в сочетании с охватом кода - правильный инструмент для меня. Я не хочу, чтобы мои тесты прерывались, когда я помещал 1 строку кода выше или ниже предыдущей, потому что это повышает производительность или так. С mockito это не проблема. С EasyMock это приведет к провалу тестов, даже если код не сломался. Это плохо. Это стоит времени, а значит и денег. Вы хотите проверить ожидаемое поведение. Вы действительно заботитесь о порядке вещей? Полагаю, в редких случаях вы можете. Затем используйте Easymock. В другом случае, я думаю, вы потратите значительно меньше времени, используя mockito, чтобы написать свои тесты.

Сердечные приветы Лоуренс

Смежные вопросы