EASYMOCK参数匹配器
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()*匹配器来匹配新添加的 User:
@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()*匹配器来匹配特定的 User:
@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()*匹配器使用“ ==” 比较参数,这意味着它在我们的例子中比较User*实例。
如果我们不使用任何匹配器,则默认使用equals() 比较参数。
对于数组,我们还有基于*Arrays.equals()方法的aryEq()*匹配器。
4. 任何匹配器
有多个 any 匹配器,例如anyInt()、anyBoolean()、*anyDouble()*等。它们指定参数应该具有给定的类型。
让我们看一个使用 anyString()将预期Email匹配 为任何string值的示例:
@Test
public void givenUserService_whenSearchForUserByEmail_thenFound() {
expect(userService.findByEmail(anyString()))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("blogdemo@itcodingman.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()匹配器来匹配null值。
在以下示例 中,如果添加的User值为 null ,我们将使用*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. 字符串匹配器
我们可以将多个有用的匹配器与string参数一起使用。
首先,我们将使用 *startsWith()*匹配器来匹配用户的电子邮件前缀:
@Test
public void whenSearchForUserByEmailStartsWith_thenFound() {
expect(userService.findByEmail(startsWith("test")))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("blogdemo@itcodingman.com");
verify(userService);
assertEquals(0,result.size());
}
同样,我们将使用 *endsWith()*匹配器作为电子邮件后缀:
@Test
public void givenUserService_whenSearchForUserByEmailEndsWith_thenFound() {
expect(userService.findByEmail(endsWith(".com")))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("blogdemo@itcodingman.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("blogdemo@itcodingman.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("blogdemo@itcodingman.com");
verify(userService);
assertEquals(0,result.size());
}
7. 数值匹配器
我们还有一些可以使用的数值匹配器。
让我们看一个使用 *lt()*匹配器将年龄参数匹配为小于 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()*来匹配年龄参数是否大于或等于 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() 和*endsWith()*来匹配不以“.com”结尾的电子邮件:
@Test
public void givenUserService_whenSearchForUserByEmailNotEndsWith_thenFound() {
expect(userService.findByEmail(not(endsWith(".com"))))
.andReturn(Collections.emptyList());
replay(userService);
List<User> result = userService.findByEmail("blogdemo@itcodingman.com");
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("blogdemo@itcodingman.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 接口有两个方法:matches() 和 appendTo()。
第一个方法包含我们的匹配器的参数验证和逻辑,而第二个用于附加匹配器字符串表示以在失败的情况下打印。