1. Overview
1.概述
In this tutorial, we’ll explore EasyMock argument matchers. We’ll discuss different types of predefined matchers and how to create a custom matcher as well.
在本教程中,我们将探讨EasyMock参数匹配器。我们将讨论不同类型的预定义匹配器以及如何创建一个自定义匹配器。
We already covered EasyMock basics in the introduction to EasyMock article, so you may need to read it first to get yourself familiar with EasyMock.
我们已经在EasyMock简介一文中介绍了EasyMock的基础知识,因此您可能需要先阅读这篇文章,以便熟悉EasyMock。
2. Simple Mocking Example
2.简单的嘲讽实例
Before we start exploring different matchers, let’s take a look at our context. Throughout this tutorial, we’ll use a pretty basic user service in our examples.
在我们开始探索不同的匹配器之前,让我们看看我们的背景。在本教程中,我们将在我们的例子中使用一个相当基本的用户服务。
Here’s our simple IUserService interface:
这里是我们简单的IUserService接口。
public interface IUserService {
public boolean addUser(User user);
public List<User> findByEmail(String email);
public List<User> findByAge(double age);
}
And the related User model:
以及相关的User模型。
public class User {
private long id;
private String firstName;
private String lastName;
private double age;
private String email;
// standard constructor, getters, setters
}
So, we’ll start by merely mocking our IUserService to use it in our examples:
因此,我们将从仅仅模拟我们的IUserService开始,在我们的例子中使用它。
private IUserService userService = mock(IUserService.class);
Now, let’s explore the EasyMock argument matchers.
现在,让我们来探索EasyMock的参数匹配器。
3. Equality Matchers
3.平等的匹配者
First, we’ll use eq() matcher to match the new added User:
首先,我们将使用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);
}
This matcher is available for both primitive and objects, and uses the equals() method for objects.
这个匹配器对原始数据和对象都可用,并且对对象使用equals()方法。
Similarly, we can use same() matcher for matching a specific User:
同样,我们可以使用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);
}
The same() matcher compares arguments using “==”, meaning it compares User instances in our case.
same()匹配器使用”==”对参数进行比较,这意味着在我们的案例中,它对User实例进行比较。
If we don’t use any matchers, arguments are compared by default using equals().
如果我们不使用任何匹配器,参数的比较默认使用equals()。
For arrays, we also have the aryEq() matcher which is based on the Arrays.equals() method.
对于数组,我们也有aryEq()匹配器,它基于Arrays.equals()方法。
4. Any Matchers
4.任何匹配者
There are multiple any matchers like anyInt(), anyBoolean(), anyDouble(),… etc. These specify that the argument should have the given type.
有多个任意匹配器,如anyInt(), anyBoolean(), anyDouble(), …等等。这些指定参数应该具有给定的类型。
Let’s see an example of using anyString() to match the expected email to be any String value:
让我们看一个使用anyString()来匹配预期的email为任何String值的例子。
@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());
}
We can also use isA() to match an argument to be an instance of a specific class:
我们还可以使用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);
}
Here, we’re asserting that we expect the addUser() method parameter to be of type User.
在这里,我们断言,我们希望addUser()方法的参数是User.类型。
5. Null Matchers
5.零匹配器
Next, we can use the isNull() and notNull() matchers to match null values.
接下来,我们可以使用isNull()和notNull()匹配器来匹配null值。
In the following example, we’ll use the isNull() matcher to match if the added User value is null:
在下面的例子中,我们将使用isNull()匹配器来匹配添加的User值是否为空。
@Test
public void givenUserService_whenAddNull_thenFail() {
expect(userService.addUser(isNull())).andReturn(false);
replay(userService);
boolean result = userService.addUser(null);
verify(userService);
assertFalse(result);
}
We can also notNull() to match if added user value is not null in a similar way:
我们也可以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 Matchers
6.字符串匹配器
There are multiple useful matchers that we can use with String arguments.
有多个有用的匹配器,我们可以用String参数来使用。
First, we’ll use the startsWith() matcher to match a user’s email prefix:
首先,我们将使用startsWith()匹配器来匹配一个用户的电子邮件前缀。
@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());
}
Similarly, we’ll use the endsWith() matcher for the email suffix:
同样地,我们将使用endsWith()匹配器来处理电子邮件后缀。
@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());
}
More generally, we can use contains() to match the email with a given substring:
更一般地说,我们可以使用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());
}
Or even match our email to a specific regex using matches():
甚至可以使用matches()将我们的电子邮件与一个特定的重合词相匹配。
@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. Number Matchers
7.数字匹配器
We also have a few matchers for numeric values that we can use.
我们也有一些数字值的匹配器,我们可以使用。
Let’ see an example of using the lt() matcher to match the age argument to be less than 100:
让我们看一个使用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());
}
Similarly, we also use geq() to match the age argument to be greater than or equal to 10:
同样,我们也使用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());
}
The available number matchers are:
可用的数字匹配器是:。
- lt() – less than the given value
- leq() – less than or equal
- gt() – greater than
- geq() – greater than or equal
8. Combine Matchers
8.组合匹配器
We can also combine multiple matchers using and(), or() and not() matchers.
我们还可以使用and()、or()和not()匹配器组合多个匹配器。
Let’s see how we can combine two matchers to verify that the age value is both greater than 10 and less than 100:
让我们看看如何结合两个匹配器来验证年龄值是否既大于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());
}
Another example we can look at is combining not() with endsWith() to match emails that don’t end with “.com”:
我们可以看的另一个例子是将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("test@example.org");
verify(userService);
assertEquals(0,result.size());
}
9. Custom Matcher
9.自定义匹配器
Finally, we’ll discuss how to create a custom EasyMock matcher.
最后,我们将讨论如何创建一个自定义的EasyMock匹配器。
The goal is to create a simple minCharCount() matcher to match strings with a length greater than or equal to the given value:
我们的目标是创建一个简单的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());
}
To create a custom argument matcher, we need to:
要创建一个自定义参数匹配器,我们需要。
- create a new class that implements the IArgumentMatcher interface
- create a static method with the new matcher name and register an instance of the class above using reportMatcher()
Let’s see both steps in our minCharCount() method that declares an anonymous class within it:
让我们看看我们的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;
}
Also, note that the IArgumentMatcher interface has two methods: matches() and appendTo().
另外,请注意,IArgumentMatcher接口有两个方法。matches()和appendTo()。
The first method contains the argument validation and logic for our matcher, while the second is used to append the matcher String representation to be printed in case of failure.
第一个方法包含了我们的匹配器的参数验证和逻辑,而第二个方法用于附加匹配器的String表示,以便在失败时打印。
10. Conclusion
10.结论
We covered EasyMock predefined argument matchers for different data types and how to create our custom matcher.
我们介绍了EasyMock为不同数据类型预定义的参数匹配器,以及如何创建我们的自定义匹配器。
The full source code for the examples is available over on GitHub.
例子的完整源代码可在GitHub上获得over。