Using Hamcrest Number Matchers – 使用Hamcrest号码匹配器

最后修改: 2018年 3月 11日

1. Overview


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


To get Hamcrest, we just need to add the following Maven dependency to our pom.xml:



The latest Hamcrest version can be found on Maven Central.

最新的Hamcrest版本可以在Maven Central上找到。

3. Proximity Matchers


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


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:


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:


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


isClose is overloaded and can be used same as with double values, but with BigDecimal objects:


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)));

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.


That’s about it for proximity matchers. Next, we’ll take a look at order matchers.


4. Order Matchers


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


The most common scenario would be using these matchers with numbers.


So, let’s go ahead and create some tests:


public void given5_whenComparesEqualTo5_thenCorrect() {
    Integer five = 5;
    assertThat(five, comparesEqualTo(five));

public void given5_whenNotComparesEqualTo7_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;

    assertThat(five, not(comparesEqualTo(seven)));

public void given7_whenGreaterThan5_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;
    assertThat(seven, is(greaterThan(five)));

public void given7_whenGreaterThanOrEqualTo5_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;
    assertThat(seven, is(greaterThanOrEqualTo(five)));

public void given5_whenGreaterThanOrEqualTo5_thenCorrect() {
    Integer five = 5;
    assertThat(five, is(greaterThanOrEqualTo(five)));

public void given3_whenLessThan5_thenCorrect() {
   Integer three = 3;
   Integer five = 5;
   assertThat(three, is(lessThan(five)));

public void given3_whenLessThanOrEqualTo5_thenCorrect() {
   Integer three = 3;
   Integer five = 5;
   assertThat(three, is(lessThanOrEqualTo(five)));

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


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:


public void givenBenjamin_whenGreaterThanAmanda_thenCorrect() {
    String amanda = "Amanda";
    String benjamin = "Benjamin";
    assertThat(benjamin, is(greaterThan(amanda)));

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.


So, it makes sense that the word “Amanda” comes before the word “Benjamin”.

因此,”阿曼达 “这个词出现在 “本杰明 “这个词之前是合理的。

4.3. Order Matchers With LocalDate Values


Same as with Strings, we can compare dates. Let’s take a look at the same examples we created above but using LocalDate objects:


public void givenToday_whenGreaterThanYesterday_thenCorrect() {
    LocalDate today =;
    LocalDate yesterday = today.minusDays(1);
    assertThat(today, is(greaterThan(yesterday)));

public void givenToday_whenLessThanTomorrow_thenCorrect() {
    LocalDate today =;
    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


So, why not create our own class and implement Comparable? That way, we can leverage order matchers to be used with custom order rules.


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:


public class Person implements Comparable<Person> {
    // ...

    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:


public void givenAmanda_whenOlderThanBenjamin_thenCorrect() {
    Person amanda = new Person("Amanda", 20);
    Person benjamin = new Person("Benjamin", 18);
    assertThat(amanda, is(greaterThan(benjamin)));

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.


5. NaN Matcher


Hamcrest provides one extra number matcher to define if a number is actually, not a number:


public void givenNaN_whenIsNotANumber_thenCorrect() {
    double zero = 0d;
    assertThat(zero / zero, is(notANumber()));

6. Conclusions


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.


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.