«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);
}
И связанная с ним модель User:
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. Any Matchers
Существует несколько any matchers, таких как anyInt(), anyBoolean(), anyDouble(),… и т. д. Они указывают, что аргумент должен иметь заданный тип.
Давайте рассмотрим пример использования anyString() для сопоставления ожидаемого электронного письма с любым строковым значением:
@Test
public void givenUserService_whenSearchForUserByEmail_thenFound() {
expect(userService.findByEmail(anyString()))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("[email protected]");
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. Сопоставители Null
Далее мы можем использовать сопоставители isNull() и notNull() для сопоставления нулевых значений.
В следующем примере мы будем использовать сопоставитель isNull() для сопоставления, если добавленное значение пользователя равно нулю:
@Test
public void givenUserService_whenAddNull_thenFail() {
expect(userService.addUser(isNull())).andReturn(false);
replay(userService);
boolean result = userService.addUser(null);
verify(userService);
assertFalse(result);
}
Мы также можем использовать notNull() для сопоставления, если добавленное значение пользователя не равно нулю в аналогичным образом:
@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("[email protected]");
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("[email protected]");
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("[email protected]");
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("[email protected]");
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: электронные письма, которые не заканчиваются на «.com»:
@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());
}
9. Custom Matcher
@Test
public void givenUserService_whenSearchForUserByEmailNotEndsWith_thenFound() {
expect(userService.findByEmail(not(endsWith(".com"))))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("[email protected]");
verify(userService);
assertEquals(0,result.size());
}
Наконец, мы обсудим, как создать собственный сопоставление EasyMock.
Цель состоит в том, чтобы создать простой сопоставитель minCharCount() для сопоставления строк, длина которых больше или равна заданному значению:
Чтобы создать собственный сопоставитель аргументов, нам необходимо:
@Test
public void givenUserService_whenSearchForUserByEmailCharCount_thenFound() {
expect(userService.findByEmail(minCharCount(5)))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("[email protected]");
verify(userService);
assertEquals(0,result.size());
}
создать новый класс, реализующий интерфейс IArgumentMatcher, создайте статический метод с новым именем сопоставления и зарегистрируйте экземпляр указанного выше класса, используя reportMatcher()
-
Давайте посмотрим на оба шага в нашем методе minCharCount(), который объявляет в нем анонимный класс:
Также обратите внимание, что интерфейс IArgumentMatcher имеет два метода:match() и appendTo().
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;
}
«Первый метод содержит проверку аргументов и логику для нашего сопоставителя, а второй используется для добавления строкового представления сопоставителя, которое будет напечатано в случае сбоя.
10. Заключение
Мы рассмотрели предопределенные сопоставители аргументов EasyMock для различных типов данных и то, как создать собственный сопоставитель.
Полный исходный код примеров доступен на GitHub.
«