Мокито против EasyMock против JMockit

Мокито против EasyMock против JMockit

1. Вступление

1.1. обзор

В этом посте мы поговорим оmocking: что это такое, зачем его использовать, а также о нескольких примерах того, как имитировать один и тот же тестовый пример с использованием некоторых из наиболее часто используемых имитирующих библиотек для Java.

Мы начнем с некоторых формальных / полуформальных определений насмешливых концепций; Затем мы представим тестируемый случай, рассмотрим примеры для каждой библиотеки и сделаем некоторые выводы. Выбранные библиотеки:Mockito,EasyMock иJMockit.

Если вы чувствуете, что уже знаете основы насмешек, возможно, вы можете перейти к пункту 2, не читая следующие три пункта.

1.2. Причины использования моков

Начнем с предположения, что вы уже кодируете, следуя некоторой методологии управляемой разработки, основанной на тестах (TDD, ATDD или BDD). Или просто, что вы хотите создать тест для существующего класса, который полагается на зависимости для достижения его функциональности.

В любом случае, при модульном тестировании класса мы хотим использоватьtest only its functionality and not that of its dependencies (либо потому, что мы доверяем их реализации, либо потому, что мы сами проверим его).

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

Эта управляемая замена -mock, она поможет вам упростить кодирование тестов и сократить время выполнения теста.

1.3. Имитация концепций и определения

Давайте посмотрим на четыре определенияarticle, написанные Мартином Фаулером, которые суммируют основы, которые каждый должен знать о mock-объектах:

  • ОбъектыDummy передаются, но на самом деле никогда не используются. Обычно они просто используются для заполнения списков параметров.

  • ОбъектыFake имеют рабочие реализации, но обычно используют какой-то ярлык, который делает их непригодными для производства (хорошим примером является база данных в памяти).

  • Stubs предоставляет стандартные ответы на звонки, сделанные во время теста, обычно не отвечая ни на что, кроме того, что запрограммировано для теста. Заглушки могут также записывать информацию о вызовах, такую ​​как заглушка шлюза электронной почты, которая запоминает сообщения, которые она «отправила», или, возможно, только сколько сообщений она «отправила».

  • Mocks - это то, о чем мы здесь говорим: объекты, предварительно запрограммированные с ожиданиями, которые формируют спецификацию вызовов, которые они ожидают получить.

1.4 To Mock or Not to Mock: That Is the Question

Not everything must be mocked. Иногда лучше провести интеграционный тест, поскольку насмешка над этим методом / функцией будет работать только с небольшой реальной пользой. В нашем тестовом примере (который будет показан в следующем пункте) это будет тестироватьLoginDao.

LoginDao будет использовать какую-то стороннюю библиотеку для доступа к БД, и издевательство над ней будет заключаться только в том, чтобы гарантировать, что параметры были подготовлены для вызова, но нам все равно нужно будет проверить, что вызов возвращает нужные данные.

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

2. Прецедент

Имея в виду все, что было в предыдущем разделе, давайте предложим довольно типичный тестовый пример и то, как мы будем тестировать его с помощью макетов (когда есть смысл использовать макеты). Это поможет нам создать общий сценарий, чтобы в дальнейшем можно было сравнивать разные библиотеки-насмешки.

2.1 Proposed Case

Предлагаемый тестовый пример будет процессом входа в систему в приложении с многоуровневой архитектурой.

Запрос на вход в систему будет обрабатываться контроллером, который использует службу, которая использует DAO (которая ищет учетные данные пользователя в БД). Мы не будем слишком углубляться в реализацию каждого слоя и сосредоточимся больше наinteractions between the components каждого слоя.

Таким образом, у нас будетLoginController, aLoginService и aLoginDAO. Давайте посмотрим на диаграмму для пояснения:

Test case diagram

2.2 Implementation

Теперь мы рассмотрим реализацию, используемую для тестового примера, чтобы мы могли понять, что происходит (или что должно произойти) в тестах.

Мы начнем с модели, используемой для всех операций,UserForm, которая будет содержать только имя пользователя и пароль (мы используем модификаторы общего доступа для упрощения) и метод получения для поляusername чтобы разрешить издевательство над этим свойством:

public class UserForm {
    public String password;
    public String username;
    public String getUsername(){
        return username;
    }
}

Давайте продолжим сLoginDAO, который будет лишен функциональности, поскольку мы хотим, чтобы его методы были там, чтобы мы могли имитировать их, когда это необходимо:

public class LoginDao {
    public int login(UserForm userForm){
        return 0;
    }
}

LoginDao будет использоватьсяLoginService в своем методеlogin. LoginService также будет иметь методsetCurrentUser, который возвращаетvoid для проверки этого издевательства.

public class LoginService {
    private LoginDao loginDao;
    private String currentUser;

    public boolean login(UserForm userForm) {
        assert null != userForm;
        int loginResults = loginDao.login(userForm);
        switch (loginResults){
            case 1:
                return true;
            default:
                return false;
        }
    }

    public void setCurrentUser(String username) {
        if(null != username){
            this.currentUser = username;
        }
    }
}

Наконец,LoginController будет использоватьLoginService для своего методаlogin. Это будет включать в себя:

  • случай, когда никакие вызовы к поддельной службе не будут сделаны.

  • случай, когда будет вызван только один метод.

  • случай, когда все методы будут вызваны.

  • случай, в котором будет проверено исключение.

public class LoginController {
    public LoginService loginService;

    public String login(UserForm userForm){
        if(null == userForm){
            return "ERROR";
        }else{
            boolean logged;

            try {
                logged = loginService.login(userForm);
            } catch (Exception e) {
                return "ERROR";
            }

            if(logged){
                loginService.setCurrentUser(userForm.getUsername());
                return "OK";
            }else{
                return "KO";
            }
        }
    }
}

Теперь, когда мы увидели, что именно мы пытаемся протестировать, давайте посмотрим, как мы будем имитировать это с каждой библиотекой.

3. Испытательная установка

3.1 Mockito

Для Mockito мы будем использовать версию2.8.9.

Самый простой способ создания и использования моков - использовать аннотации@Mock и@InjectMocks. Первый создаст макет для класса, используемого для определения поля, а второй попытается вставить указанные созданные макеты в аннотированный макет.

Есть и другие аннотации, такие как@Spy, которые позволяют вам создать частичный макет (макет, который использует обычную реализацию в немокаемых методах).

При этом вам необходимо вызватьMockitoAnnotations.initMocks(this) перед выполнением любых тестов, которые будут использовать указанные имитаторы для работы всей этой «магии». Обычно это делается с помощью аннотированного метода@Before. Вы также можете использоватьMockitoJUnitRunner.

public class LoginControllerTest {

    @Mock
    private LoginDao loginDao;

    @Spy
    @InjectMocks
    private LoginService spiedLoginService;

    @Mock
    private LoginService loginService;

    @InjectMocks
    private LoginController loginController;

    @Before
    public void setUp() {
        loginController = new LoginController();
        MockitoAnnotations.initMocks(this);
    }
}

3.2 EasyMock

Для EasyMock мы будем использовать версию3.4 (Javadoc). Обратите внимание, что с EasyMock, чтобы моки начали «работать», вы должны вызватьEasyMock.replay(mock) для каждого метода тестирования, иначе вы получите исключение.

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

Моки создаются с аннотацией@Mock, а тестируемый объект - с аннотацией@TestSubject (которая получит свои зависимости, введенные из созданных моков). Тестируемый объект должен быть создан in-line.

@RunWith(EasyMockRunner.class)
public class LoginControllerTest {

    @Mock
    private LoginDao loginDao;

    @Mock
    private LoginService loginService;

    @TestSubject
    private LoginController loginController = new LoginController();
}

3.3. JMockit

Для JMockit мы будем использовать версию1.24 (Javadoc), поскольку версия 1.25 еще не выпущена (по крайней мере, на момент написания этой статьи).

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

Моки определяются с помощью аннотации@Injectable (которая создаст только один экземпляр макета) или с помощью аннотации@Mocked (которая будет создавать макеты для каждого экземпляра класса аннотированного поля).

Тестируемый экземпляр создается (и вводятся его имитируемые зависимости) с использованием аннотации@Tested.

@RunWith(JMockit.class)
public class LoginControllerTest {

    @Injectable
    private LoginDao loginDao;

    @Injectable
    private LoginService loginService;

    @Tested
    private LoginController loginController;
}

4. Проверка отсутствия вызовов для имитации

4.1. Mockito

Для проверки того, что макет не получил вызовов в Mockito, у вас есть методverifyZeroInteractions(), который принимает макет.

@Test
public void assertThatNoMethodHasBeenCalled() {
    loginController.login(null);
    Mockito.verifyZeroInteractions(loginService);
}

4.2. EasyMock

Чтобы проверить, что макет не получил вызовов, вы просто не указываете поведение, вы воспроизводите макет повторно и, наконец, проверяете его.

@Test
public void assertThatNoMethodHasBeenCalled() {
    EasyMock.replay(loginService);
    loginController.login(null);
    EasyMock.verify(loginService);
}

4.3. JMockit

Для проверки того, что макет не получил звонков, вы просто не указываете ожидания для этого макета и выполняетеFullVerifications(mock) для указанного макета.

@Test
public void assertThatNoMethodHasBeenCalled() {
    loginController.login(null);
    new FullVerifications(loginService) {};
}

5. Определение вызовов имитированных методов и проверка вызовов имитаций

5.1. Mockito

Дляmocking method calls вы можете использоватьMockito.when(mock.method(args)).thenReturn(value). Здесь вы можете возвращать разные значения для более чем одного вызова, просто добавляя их как дополнительные параметры:thenReturn(value1, value2, value-n, …).

Обратите внимание, что с этим синтаксисом нельзя имитировать методы возврата void. В указанных случаях вы будете использовать проверку указанного метода (как показано в строке 11).

Дляverifying calls в макете вы можете использоватьMockito.verify(mock).method(args), а также можете проверить, что больше не было обращений к макету с помощьюverifyNoMoreInteractions(mock).

Дляverifying args вы можете передавать определенные значения или использовать предопределенные сопоставители, такие какany(),anyString(),anyInt().. Таких сопоставителей гораздо больше и даже возможность определять ваши сопоставители, которые мы увидим в следующих примерах.

@Test
public void assertTwoMethodsHaveBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    Mockito.when(loginService.login(userForm)).thenReturn(true);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    Mockito.verify(loginService).login(userForm);
    Mockito.verify(loginService).setCurrentUser("foo");
}

@Test
public void assertOnlyOneMethodHasBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    Mockito.when(loginService.login(userForm)).thenReturn(false);

    String login = loginController.login(userForm);

    Assert.assertEquals("KO", login);
    Mockito.verify(loginService).login(userForm);
    Mockito.verifyNoMoreInteractions(loginService);
}

5.2. EasyMock

Дляmocking method calls вы используетеEasyMock.expect(mock.method(args)).andReturn(value).

Дляverifying calls для имитации вы можете использоватьEasyMock.verify(mock), но вы должны называть егоalways after, вызываяEasyMock.replay(mock).

Дляverifying args вы можете передать определенные значения или у вас есть предопределенные сопоставители, такие как isA(Class.class),anyString(),anyInt() иlot more такого типа сопоставителей и снова возможность определять ваши сопоставители.

@Test
public void assertTwoMethodsHaveBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    EasyMock.expect(loginService.login(userForm)).andReturn(true);
    loginService.setCurrentUser("foo");
    EasyMock.replay(loginService);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    EasyMock.verify(loginService);
}

@Test
public void assertOnlyOneMethodHasBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    EasyMock.expect(loginService.login(userForm)).andReturn(false);
    EasyMock.replay(loginService);

    String login = loginController.login(userForm);

    Assert.assertEquals("KO", login);
    EasyMock.verify(loginService);
}

5.3. JMockit

С JMockit вы определилиsteps для тестирования: запись, воспроизведение и проверка.

Record выполняется в новом блокеExpectations()\{\{}} (в котором вы можете определить действия для нескольких макетов),replay выполняется просто путем вызова метода тестируемого класса (который должен вызывать некоторые макеты. объект), аverification выполняется внутри нового блокаVerifications()\{\{}} (в котором вы можете определить проверки для нескольких моков).

Дляmocking method calls вы можете использоватьmock.method(args); result = value; внутри любого блокаExpectations. Здесь вы можете возвращать разные значения для более чем одного вызова, просто используяreturns(value1, value2, …, valuen); вместоresult = value;.

Дляverifying calls для имитации вы можете использовать новые проверки()\{\{mock.call(value)}} илиnew Verifications(mock)\{\{}} для проверки каждого ранее определенного ожидаемого вызова.

Дляverifying args вы можете передать определенные значения, или у вас естьpredefined values, напримерany,anyString,anyLong, и многие другие подобные специальные значения и снова возможность определять ваши сопоставители (это должны быть сопоставители Hamcrest).

@Test
public void assertTwoMethodsHaveBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    new Expectations() {{
        loginService.login(userForm); result = true;
        loginService.setCurrentUser("foo");
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    new FullVerifications(loginService) {};
}

@Test
public void assertOnlyOneMethodHasBeenCalled() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    new Expectations() {{
        loginService.login(userForm); result = false;
        // no expectation for setCurrentUser
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("KO", login);
    new FullVerifications(loginService) {};
}

6. Мокинг бросок исключения

6.1. Mockito

Выделение исключения можно смоделировать с помощью.thenThrow(ExceptionClass.class) послеMockito.when(mock.method(args)).

@Test
public void mockExceptionThrowin() {
    UserForm userForm = new UserForm();
    Mockito.when(loginService.login(userForm)).thenThrow(IllegalArgumentException.class);

    String login = loginController.login(userForm);

    Assert.assertEquals("ERROR", login);
    Mockito.verify(loginService).login(userForm);
    Mockito.verifyZeroInteractions(loginService);
}

6.2. EasyMock

Выделение исключения можно смоделировать с помощью.andThrow(new ExceptionClass()) после вызоваEasyMock.expect(…).

@Test
public void mockExceptionThrowing() {
    UserForm userForm = new UserForm();
    EasyMock.expect(loginService.login(userForm)).andThrow(new IllegalArgumentException());
    EasyMock.replay(loginService);

    String login = loginController.login(userForm);

    Assert.assertEquals("ERROR", login);
    EasyMock.verify(loginService);
}

6.3. JMockit

Дразнить насмешку с JMockito особенно легко. Просто верните Исключение как результат осмеянного вызова метода вместо «нормального» возврата.

@Test
public void mockExceptionThrowing() {
    UserForm userForm = new UserForm();
    new Expectations() {{
        loginService.login(userForm); result = new IllegalArgumentException();
        // no expectation for setCurrentUser
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("ERROR", login);
    new FullVerifications(loginService) {};
}

7. Издевательство над объектом для обхода

7.1. Mockito

Вы также можете создать макет для передачи в качестве аргумента для вызова метода. С Mockito вы можете сделать это с помощью одной строки.

@Test
public void mockAnObjectToPassAround() {
    UserForm userForm = Mockito.when(Mockito.mock(UserForm.class).getUsername())
      .thenReturn("foo").getMock();
    Mockito.when(loginService.login(userForm)).thenReturn(true);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    Mockito.verify(loginService).login(userForm);
    Mockito.verify(loginService).setCurrentUser("foo");
}

7.2. EasyMock

Моки могут быть созданы с помощьюEasyMock.mock(Class.class). После этого вы можете использоватьEasyMock.expect(mock.method()), чтобы подготовить его к выполнению, всегда не забывая вызыватьEasyMock.replay(mock) перед его использованием.

@Test
public void mockAnObjectToPassAround() {
    UserForm userForm = EasyMock.mock(UserForm.class);
    EasyMock.expect(userForm.getUsername()).andReturn("foo");
    EasyMock.expect(loginService.login(userForm)).andReturn(true);
    loginService.setCurrentUser("foo");
    EasyMock.replay(userForm);
    EasyMock.replay(loginService);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    EasyMock.verify(userForm);
    EasyMock.verify(loginService);
}

7.3. JMockit

Чтобы смоделировать объект только для одного метода, вы можете просто передать его в качестве параметра методу тестирования. Тогда вы можете создавать ожидания, как с любой другой насмешкой.

@Test
public void mockAnObjectToPassAround(@Mocked UserForm userForm) {
    new Expectations() {{
        userForm.getUsername(); result = "foo";
        loginService.login(userForm); result = true;
        loginService.setCurrentUser("foo");
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    new FullVerifications(loginService) {};
    new FullVerifications(userForm) {};
}

8. Пользовательское сопоставление аргументов

8.1. Mockito

Иногда сопоставление аргументов для имитируемых вызовов должно быть немного сложнее, чем просто фиксированное значение илиanyString(). Для этих случаев у Mockito есть класс сопоставления, который используется сargThat(ArgumentMatcher<>).

@Test
public void argumentMatching() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // default matcher
    Mockito.when(loginService.login(Mockito.any(UserForm.class))).thenReturn(true);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    Mockito.verify(loginService).login(userForm);
    // complex matcher
    Mockito.verify(loginService).setCurrentUser(ArgumentMatchers.argThat(
        new ArgumentMatcher() {
            @Override
            public boolean matches(String argument) {
                return argument.startsWith("foo");
            }
        }
    ));
}

8.2. EasyMock

Сопоставление настраиваемых аргументов с EasyMock немного сложнее, поскольку вам нужно создать статический метод, в котором вы создаете фактическое сопоставление, а затем сообщаете об этом с помощьюEasyMock.reportMatcher(IArgumentMatcher).

Как только этот метод создан, вы используете его по своему ложному ожиданию с вызовом метода (как показано в примере в строке).

@Test
public void argumentMatching() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // default matcher
    EasyMock.expect(loginService.login(EasyMock.isA(UserForm.class))).andReturn(true);
    // complex matcher
    loginService.setCurrentUser(specificArgumentMatching("foo"));
    EasyMock.replay(loginService);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    EasyMock.verify(loginService);
}

private static String specificArgumentMatching(String expected) {
    EasyMock.reportMatcher(new IArgumentMatcher() {
        @Override
        public boolean matches(Object argument) {
            return argument instanceof String
              && ((String) argument).startsWith(expected);
        }

        @Override
        public void appendTo(StringBuffer buffer) {
            //NOOP
        }
    });
    return null;
}

8.3. JMockit

Сопоставление настраиваемых аргументов с JMockit выполняется с помощью специального методаwithArgThat(Matcher) (который принимает объектыHamcrest ’sMatcher).

@Test
public void argumentMatching() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // default matcher
    new Expectations() {{
        loginService.login((UserForm) any);
        result = true;
        // complex matcher
        loginService.setCurrentUser(withArgThat(new BaseMatcher() {
            @Override
            public boolean matches(Object item) {
                return item instanceof String && ((String) item).startsWith("foo");
            }

            @Override
            public void describeTo(Description description) {
                //NOOP
            }
        }));
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    new FullVerifications(loginService) {};
}

9. Частичное издевательство

9.1. Mockito

Mockito позволяет частичное моделирование (моделирование, которое использует реальную реализацию вместо вызовов mocked-метода в некоторых своих методах) двумя способами.

Вы можете использовать.thenCallRealMethod() в обычном определении вызова фиктивного метода, или вы можете создатьspy вместо фиктивного, и в этом случае поведение по умолчанию для этого будет заключаться в вызове реальной реализации во всех не- издевался над методами.

@Test
public void partialMocking() {
    // use partial mock
    loginController.loginService = spiedLoginService;
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // let service's login use implementation so let's mock DAO call
    Mockito.when(loginDao.login(userForm)).thenReturn(1);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    // verify mocked call
    Mockito.verify(spiedLoginService).setCurrentUser("foo");
}

9.2. EasyMock

Частичное моделирование также становится немного сложнее с EasyMock, так как вам нужно определить, какие методы будут моделироваться при создании макета.

Это делается с помощьюEasyMock.partialMockBuilder(Class.class).addMockedMethod(“methodName”).createMock(). Как только это будет сделано, вы можете использовать макет, как любой другой не частичный макет.

@Test
public void partialMocking() {
    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // use partial mock
    LoginService loginServicePartial = EasyMock.partialMockBuilder(LoginService.class)
      .addMockedMethod("setCurrentUser").createMock();
    loginServicePartial.setCurrentUser("foo");
    // let service's login use implementation so let's mock DAO call
    EasyMock.expect(loginDao.login(userForm)).andReturn(1);

    loginServicePartial.setLoginDao(loginDao);
    loginController.loginService = loginServicePartial;

    EasyMock.replay(loginDao);
    EasyMock.replay(loginServicePartial);

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    // verify mocked call
    EasyMock.verify(loginServicePartial);
    EasyMock.verify(loginDao);
}

9.3. JMockit

Частичное издевательство с JMockit особенно легко. Каждый вызов метода, для которого не было определено фиктивное поведение вExpectations()\{\{}}, использует «настоящую» реализацию.

В этом случае, поскольку дляLoginService.login(UserForm) не ожидается никаких ожиданий, выполняется фактическая реализация (и вызовLoginDAO.login(UserForm)).

@Test
public void partialMocking() {
    // use partial mock
    LoginService partialLoginService = new LoginService();
    partialLoginService.setLoginDao(loginDao);
    loginController.loginService = partialLoginService;

    UserForm userForm = new UserForm();
    userForm.username = "foo";
    // let service's login use implementation so let's mock DAO call
    new Expectations() {{
        loginDao.login(userForm); result = 1;
        // no expectation for loginService.login
        partialLoginService.setCurrentUser("foo");
    }};

    String login = loginController.login(userForm);

    Assert.assertEquals("OK", login);
    // verify mocked call
    new FullVerifications(partialLoginService) {};
    new FullVerifications(loginDao) {};
}

10. Заключение

В этом посте мы сравнили три имитационные библиотеки Java, каждая из которых имеет свои сильные и слабые стороны.

  • Все три из них -easily configured с аннотациями, которые помогут вам определить макеты и тестируемый объект, с бегунами, чтобы сделать имитацию инъекции максимально безболезненной.

    • Мы бы сказали, что Mockito здесь выиграет, так как у него есть специальная аннотация для частичных имитаторов, но JMockit даже не нуждается в нем, так что давайте предположим, что это связь между этими двумя.

  • Все три из них более или менее соответствуютrecord-replay-verify pattern, но, по нашему мнению, лучше всего для этого используется JMockit, поскольку он заставляет вас использовать их в блоках, поэтому тесты становятся более структурированными.

  • Easiness использования важен, чтобы вы могли как можно меньше работать над определением ваших тестов. JMockit будет выбранной опцией для его фиксированной всегда одинаковой структуры.

  • Mockito более или менее известен, так чтоcommunity будет больше.

  • Необходимость вызыватьreplay каждый раз, когда вы хотите использовать макет, - это явныйno-go, поэтому мы поставим минус для EasyMock.

  • Consistency/simplicity также важен для меня. Нам понравился способ возврата результатов JMockit, который одинаков для «нормальных» результатов и исключений.

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

full implementation этого руководства можно найти наthe GitHub project, поэтому не стесняйтесь загружать его и играть с ним.