1. Overview
1.概述
Hamcrest provides static matchers to help make unit test assertions simpler and more legible. You can get started exploring some of the available matchers here.
Hamcrest 提供了静态匹配器,以帮助使单元测试断言更简单、更清晰。您可以开始探索一些可用的匹配器这里。
In this article, we’ll dive deeper into the number-related matchers.
在这篇文章中,我们将深入探讨与数字相关的匹配器。
2. Setup
2.设置
To get Hamcrest, we just need to add the following Maven dependency to our pom.xml:
要获得Hamcrest,我们只需在pom.xml中添加以下Maven依赖项。
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
</dependency>
The latest Hamcrest version can be found on Maven Central.
最新的Hamcrest版本可以在Maven Central上找到。
3. Proximity Matchers
3.近距离匹配器
The first set of matchers that we’re going to take a look at are the ones that check if some element is close to a value +/- an error.
我们要看的第一组匹配器是那些检查某些元素是否接近一个值+/-一个误差的匹配器。
More formally:
更为正式的是。
value - error <= element <= value + error
If the comparison above is true, the assertion will pass.
如果上面的比较是真的,断言就会通过。
Let’s see it in action!
让我们看看它的行动
3.1. isClose With Double Values
3.1.isClose与Double值
Let’s say that we have a number stored in a double variable called actual. And, we want to test if actual is close to 1 +/- 0.5.
假设我们有一个数字存储在一个名为actual的双变量中。而且,我们想测试actual是否接近1 +/- 0.5。
That is:
就是说。
1 - 0.5 <= actual <= 1 + 0.5
0.5 <= actual <= 1.5
Now let’s create a unit test using isClose matcher:
现在让我们使用isClosematcher创建一个单元测试。
@Test
public void givenADouble_whenCloseTo_thenCorrect() {
double actual = 1.3;
double operand = 1;
double error = 0.5;
assertThat(actual, closeTo(operand, error));
}
As 1.3 is between 0.5 and 1.5, the test will pass. Same way, we can test the negative scenario:
由于1.3在0.5和1.5之间,测试将通过。同样,我们可以测试负面情况。
@Test
public void givenADouble_whenNotCloseTo_thenCorrect() {
double actual = 1.6;
double operand = 1;
double error = 0.5;
assertThat(actual, not(closeTo(operand, error)));
}
Now, let’s take a look at a similar situation with a different type of variables.
现在,让我们来看看一个类似的情况,有不同类型的变量。
3.2. isClose With BigDecimal Values
3.2.isClose与BigDecimal值
isClose is overloaded and can be used same as with double values, but with BigDecimal objects:
isClose是重载的,可以像使用双倍值一样使用,但可以使用BigDecimal对象。
@Test
public void givenABigDecimal_whenCloseTo_thenCorrect() {
BigDecimal actual = new BigDecimal("1.0003");
BigDecimal operand = new BigDecimal("1");
BigDecimal error = new BigDecimal("0.0005");
assertThat(actual, is(closeTo(operand, error)));
}
@Test
public void givenABigDecimal_whenNotCloseTo_thenCorrect() {
BigDecimal actual = new BigDecimal("1.0006");
BigDecimal operand = new BigDecimal("1");
BigDecimal error = new BigDecimal("0.0005");
assertThat(actual, is(not(closeTo(operand, error))));
}
Please note that the is matcher only decorates other matchers without adding extra logic. It just makes the whole assertion more readable.
请注意,is匹配器只是装饰其他匹配器,并没有添加额外的逻辑。它只是让整个断言更容易阅读。
That’s about it for proximity matchers. Next, we’ll take a look at order matchers.
这就是近似匹配器的情况。接下来,我们将看一下顺序匹配器。
4. Order Matchers
4.订单匹配器
As their name says, these matchers help make assertions regarding the order.
正如它们的名字所言,这些匹配器有助于做出关于订单的断言。。
There are five of them:
他们有五个人。
- comparesEqualTo
- greaterThan
- greaterThanOrEqualTo
- lessThan
- lessThanOrEqualTo
They’re pretty much self-explanatory, but let’s see some examples.
它们几乎是不言自明的,但让我们看看一些例子。
4.1. Order Matchers With Integer Values
4.1.带有整数V值的顺序匹配器
The most common scenario would be using these matchers with numbers.
最常见的情况是将这些匹配器用于数字。
So, let’s go ahead and create some tests:
因此,让我们继续前进,创建一些测试。
@Test
public void given5_whenComparesEqualTo5_thenCorrect() {
Integer five = 5;
assertThat(five, comparesEqualTo(five));
}
@Test
public void given5_whenNotComparesEqualTo7_thenCorrect() {
Integer seven = 7;
Integer five = 5;
assertThat(five, not(comparesEqualTo(seven)));
}
@Test
public void given7_whenGreaterThan5_thenCorrect() {
Integer seven = 7;
Integer five = 5;
assertThat(seven, is(greaterThan(five)));
}
@Test
public void given7_whenGreaterThanOrEqualTo5_thenCorrect() {
Integer seven = 7;
Integer five = 5;
assertThat(seven, is(greaterThanOrEqualTo(five)));
}
@Test
public void given5_whenGreaterThanOrEqualTo5_thenCorrect() {
Integer five = 5;
assertThat(five, is(greaterThanOrEqualTo(five)));
}
@Test
public void given3_whenLessThan5_thenCorrect() {
Integer three = 3;
Integer five = 5;
assertThat(three, is(lessThan(five)));
}
@Test
public void given3_whenLessThanOrEqualTo5_thenCorrect() {
Integer three = 3;
Integer five = 5;
assertThat(three, is(lessThanOrEqualTo(five)));
}
@Test
public void given5_whenLessThanOrEqualTo5_thenCorrect() {
Integer five = 5;
assertThat(five, is(lessThanOrEqualTo(five)));
}
Makes sense, right? Please note how simple is to understand what the predicates are asserting.
有道理,对吗?请注意,理解谓词所断言的内容是多么简单。
4.2. Order Matchers With String Values
4.2.带有字符串值的顺序匹配器
Even though comparing numbers makes complete sense, many times it’s useful to compare other types of elements. That’s why order matchers can be applied to any class that implements the Comparable interface.
尽管比较数字是完全有意义的,但很多时候,比较其他类型的元素也是有用的。这就是为什么顺序匹配器可以应用于任何实现Comparable 接口的类。
Let’s see some examples with Strings:
让我们看看一些使用字符串的例子:。
@Test
public void givenBenjamin_whenGreaterThanAmanda_thenCorrect() {
String amanda = "Amanda";
String benjamin = "Benjamin";
assertThat(benjamin, is(greaterThan(amanda)));
}
@Test
public void givenAmanda_whenLessThanBenajmin_thenCorrect() {
String amanda = "Amanda";
String benjamin = "Benjamin";
assertThat(amanda, is(lessThan(benjamin)));
}
String implements alphabetical order in compareTo method from the Comparable interface.
String实现了compareTo方法中的字母顺序,该方法来自Comparable接口。
So, it makes sense that the word “Amanda” comes before the word “Benjamin”.
因此,”阿曼达 “这个词出现在 “本杰明 “这个词之前是合理的。
4.3. Order Matchers With LocalDate Values
4.3.带有LocalDate值的订单匹配器
Same as with Strings, we can compare dates. Let’s take a look at the same examples we created above but using LocalDate objects:
与字符串一样,我们可以比较日期。让我们看一下我们上面创建的同样的例子,但使用LocalDate对象。
@Test
public void givenToday_whenGreaterThanYesterday_thenCorrect() {
LocalDate today = LocalDate.now();
LocalDate yesterday = today.minusDays(1);
assertThat(today, is(greaterThan(yesterday)));
}
@Test
public void givenToday_whenLessThanTomorrow_thenCorrect() {
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
assertThat(today, is(lessThan(tomorrow)));
}
It’s very nice to see that the statement assertThat(today, is(lessThan(tomorrow))) is close to regular English.
很高兴看到语句assertThat(today, is(lessThan(tomorrow))接近于普通英语。
4.4. Order Matchers With Custom Classes
4.4.使用自定义类的订单匹配器es
So, why not create our own class and implement Comparable? That way, we can leverage order matchers to be used with custom order rules.
因此,为什么不创建我们自己的类并实现Comparable?这样,我们可以利用订单匹配器来使用自定义订单规则。
Let’s start by creating a Person bean:
让我们从创建一个Person Bean开始。
public class Person {
String name;
int age;
// standard constructor, getters and setters
}
Now, let’s implement Comparable:
现在,我们来实现Comparable。
public class Person implements Comparable<Person> {
// ...
@Override
public int compareTo(Person o) {
if (this.age == o.getAge()) return 0;
if (this.age > o.getAge()) return 1;
else return -1;
}
}
Our compareTo implementation compares two people by their age. Let’s now create a couple of new tests:
我们的compareTo实现根据两个人的年龄进行比较。现在让我们创建几个新的测试。
@Test
public void givenAmanda_whenOlderThanBenjamin_thenCorrect() {
Person amanda = new Person("Amanda", 20);
Person benjamin = new Person("Benjamin", 18);
assertThat(amanda, is(greaterThan(benjamin)));
}
@Test
public void
givenBenjamin_whenYoungerThanAmanda_thenCorrect() {
Person amanda = new Person("Amanda", 20);
Person benjamin = new Person("Benjamin", 18);
assertThat(benjamin, is(lessThan(amanda)));
}
Matchers will now work based on our compareTo logic.
匹配器现在将基于我们的compareTo逻辑工作。
5. NaN Matcher
5.NaN匹配器
Hamcrest provides one extra number matcher to define if a number is actually, not a number:
Hamcrest提供了一个额外的数字匹配器来定义一个数字是否是,不是一个数字。
@Test
public void givenNaN_whenIsNotANumber_thenCorrect() {
double zero = 0d;
assertThat(zero / zero, is(notANumber()));
}
6. Conclusions
6.结论
As you can see, number matchers are very useful to simplify common assertions.
正如你所看到的,数字匹配器对于简化常见断言非常有用。
What’s more, Hamcrest matchers in general, are self-explanatory and easy to read.
更重要的是,一般来说,Hamcrest的匹配器是不言自明的,易于阅读的。
All this, plus the ability to combine matchers with custom comparison logic, make them a powerful tool for most projects out there.
所有这些,加上将匹配器与自定义比较逻辑相结合的能力,使它们成为大多数项目的强大工具。
The full implementation of the examples from this article can be found over on GitHub.
本文例子的完整实现可以在GitHub上找到over。