Перейти к основному содержимому

Сопоставители аргументов EasyMock

· 6 мин. чтения

1. Обзор

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

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

2. Простой насмешливый пример

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

Вот наш простой интерфейс IUserService :

public interface IUserService {
public boolean addUser(User user);
public List<User> findByEmail(String email);
public List<User> findByAge(double age);
}

И связанная модель пользователя :

public class User {
private long id;
private String firstName;
private String lastName;
private double age;
private String email;

// standard constructor, getters, setters
}

Итак, мы начнем просто с макета нашего IUserService , чтобы использовать его в наших примерах:

private IUserService userService = mock(IUserService.class);

Теперь давайте рассмотрим средства сопоставления аргументов EasyMock.

3. Сопоставители равенства

Во- первых, мы будем использовать сопоставитель eq() для сопоставления с новым добавленным пользователем :

@Test
public void givenUserService_whenAddNewUser_thenOK() {
expect(userService.addUser(eq(new User()))).andReturn(true);
replay(userService);

boolean result = userService.addUser(new User());
verify(userService);
assertTrue(result);
}

Этот сопоставитель доступен как для примитивов, так и для объектов, и использует метод equals() для объектов .

Точно так же мы можем использовать сопоставитель same() для сопоставления с конкретным пользователем :

@Test
public void givenUserService_whenAddSpecificUser_thenOK() {
User user = new User();

expect(userService.addUser(same(user))).andReturn(true);
replay(userService);

boolean result = userService.addUser(user);
verify(userService);
assertTrue(result);
}

Сопоставитель same() сравнивает аргументы, используя « == » , что означает, что в нашем случае он сравнивает экземпляры пользователя .

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

Для массивов у нас также есть сопоставитель aryEq() , основанный на методе Arrays.equals() .

4. Любые совпадения

Существует несколько любых сопоставителей, таких как anyInt() , anyBoolean() , anyDouble() ,… и т. д. Они указывают, что аргумент должен иметь заданный тип.

Давайте посмотрим на пример использования anyString() для сопоставления ожидаемого электронного письма с любым строковым значением:

@Test
public void givenUserService_whenSearchForUserByEmail_thenFound() {
expect(userService.findByEmail(anyString()))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

Мы также можем использовать isA() для сопоставления аргумента с экземпляром определенного класса:

@Test
public void givenUserService_whenAddUser_thenOK() {
expect(userService.addUser(isA(User.class))).andReturn(true);
replay(userService);

boolean result = userService.addUser(new User());
verify(userService);
assertTrue(result);
}

Здесь мы утверждаем, что ожидаем, что параметр метода addUser() будет иметь тип User.

5. Нулевые совпадения

Затем мы можем использовать сопоставители isNull() и notNull() для сопоставления нулевых значений.

В следующем примере мы будем использовать сопоставитель isNull() для сопоставления, если добавленное значение User равно null:

@Test
public void givenUserService_whenAddNull_thenFail() {
expect(userService.addUser(isNull())).andReturn(false);
replay(userService);

boolean result = userService.addUser(null);
verify(userService);
assertFalse(result);
}

Мы также можем использовать notNull() для сопоставления, если добавленное пользовательское значение не равно null, аналогичным образом:

@Test
public void givenUserService_whenAddNotNull_thenOK() {
expect(userService.addUser(notNull())).andReturn(true);
replay(userService);

boolean result = userService.addUser(new User());
verify(userService);
assertTrue(result);
}

6. Сопоставители строк

Есть несколько полезных сопоставителей, которые мы можем использовать со строковыми аргументами.

Во-первых, мы будем использовать сопоставитель startWith() для сопоставления префикса электронной почты пользователя:

@Test
public void whenSearchForUserByEmailStartsWith_thenFound() {
expect(userService.findByEmail(startsWith("test")))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

Точно так же мы будем использовать сопоставитель endWith() для суффикса электронной почты:

@Test
public void givenUserService_whenSearchForUserByEmailEndsWith_thenFound() {
expect(userService.findByEmail(endsWith(".com")))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

В более общем случае мы можем использовать contains() для сопоставления электронной почты с заданной подстрокой:

@Test
public void givenUserService_whenSearchForUserByEmailContains_thenFound() {
expect(userService.findByEmail(contains("@")))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

Или даже сопоставьте нашу электронную почту с определенным регулярным выражением, используя match () :

@Test
public void givenUserService_whenSearchForUserByEmailMatches_thenFound() {
expect(userService.findByEmail(matches(".+\\@.+\\..+")))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

7. Сопоставители чисел

У нас также есть несколько сопоставителей для числовых значений, которые мы можем использовать.

Давайте посмотрим на пример использования сопоставителя lt() для сопоставления аргумента age с значением меньше 100:

@Test
public void givenUserService_whenSearchForUserByAgeLessThan_thenFound() {
expect(userService.findByAge(lt(100.0)))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByAge(20);
verify(userService);
assertEquals(0,result.size());
}

Точно так же мы также используем geq() , чтобы аргумент age был больше или равен 10:

@Test
public void givenUserService_whenSearchForUserByAgeGreaterThan_thenFound() {
expect(userService.findByAge(geq(10.0)))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByAge(20);
verify(userService);
assertEquals(0,result.size());
}

Доступные средства сопоставления чисел:

  • lt() – меньше заданного значения
  • leq() – меньше или равно
  • gt() – больше, чем
  • geq() — больше или равно

8. Комбинируйте матчеры

Мы также можем комбинировать несколько сопоставителей, используя сопоставители and() , or() и not() .

Давайте посмотрим, как мы можем объединить два сопоставителя, чтобы убедиться, что значение возраста больше 10 и меньше 100:

@Test
public void givenUserService_whenSearchForUserByAgeRange_thenFound() {
expect(userService.findByAge(and(gt(10.0),lt(100.0))))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByAge(20);
verify(userService);
assertEquals(0,result.size());
}

Другой пример, на который мы можем обратить внимание, — это комбинация not() с endWith() для сопоставления адресов электронной почты, которые не заканчиваются на «.com»:

@Test
public void givenUserService_whenSearchForUserByEmailNotEndsWith_thenFound() {
expect(userService.findByEmail(not(endsWith(".com"))))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.org");
verify(userService);
assertEquals(0,result.size());
}

9. Пользовательский матчер

Наконец, мы обсудим, как создать собственный сопоставитель EasyMock.

Цель состоит в том, чтобы создать простой сопоставитель minCharCount() для сопоставления строк с длиной, большей или равной заданному значению:

@Test
public void givenUserService_whenSearchForUserByEmailCharCount_thenFound() {
expect(userService.findByEmail(minCharCount(5)))
.andReturn(Collections.emptyList());
replay(userService);

List<User> result = userService.findByEmail("test@example.com");
verify(userService);
assertEquals(0,result.size());
}

Чтобы создать собственный сопоставитель аргументов, нам необходимо:

  • создайте новый класс, реализующий интерфейс IArgumentMatcher
  • создайте статический метод с новым именем сопоставления и зарегистрируйте экземпляр класса выше, используя reportMatcher()

Давайте посмотрим на оба шага в нашем методе minCharCount() , в котором объявляется анонимный класс:

public static String minCharCount(int value){
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object argument) {
return argument instanceof String
&& ((String) argument).length() >= value;
}

@Override
public void appendTo(StringBuffer buffer) {
buffer.append("charCount(\"" + value + "\")");
}
});
return null;
}

Также обратите внимание, что интерфейс IArgumentMatcher имеет два метода: match( ) и appendTo().

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

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

Мы рассмотрели предопределенные средства сопоставления аргументов EasyMock для различных типов данных и способы создания нашего собственного средства сопоставления.

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