1. 概述
Hamcrest 提供静态匹配器,帮助简化单元测试断言并提升可读性。你可以从这里开始探索部分可用匹配器。
本文将深入讲解数字相关的匹配器。
2. 环境配置
引入 Hamcrest 只需在 pom.xml
中添加以下 Maven 依赖:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
</dependency>
最新版本可在 Maven Central 查询。
3. 近似值匹配器
第一组匹配器用于检测元素是否接近某个值(允许误差范围内)。
形式化定义:
value - error <= element <= value + error
若上述条件成立,断言通过。我们直接看代码示例:
3.1. isClose
处理 Double 类型
假设有一个 double
变量 actual
,需验证其是否接近 1 ± 0.5
:
即:
1 - 0.5 <= actual <= 1 + 0.5
0.5 <= actual <= 1.5
使用 isClose
匹配器编写测试:
@Test
public void givenADouble_whenCloseTo_thenCorrect() {
double actual = 1.3;
double operand = 1;
double error = 0.5;
assertThat(actual, closeTo(operand, error));
}
✅ 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)));
}
3.2. isClose
处理 BigDecimal 类型
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))));
}
⚠️ is
匹配器仅装饰其他匹配器,不增加额外逻辑,仅提升可读性。
4. 顺序匹配器
顾名思义,这类匹配器用于验证元素间的顺序关系。
包含五种匹配器:
-
comparesEqualTo
-
greaterThan
-
greaterThanOrEqualTo
-
lessThan
-
lessThanOrEqualTo
4.1. 处理 Integer 类型
最常见场景是数字比较,直接看示例:
@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)));
}
4.2. 处理 String 类型
虽然数字比较很直观,但顺序匹配器可应用于任何实现 Comparable
接口的类。
以 String
为例:
@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
通过 compareTo
实现字典序比较,因此 "Amanda" 排在 "Benjamin" 前面。
4.3. 处理 LocalDate 类型
日期比较同样适用,看 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)));
}
assertThat(today, is(lessThan(tomorrow)))
的可读性接近自然语言。
4.4. 处理自定义类
通过实现 Comparable
接口,可为自定义类定义排序规则。
创建 Person
类:
public class Person {
String name;
int age;
// 标准构造器、getter/setter
}
实现 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;
}
}
按年龄比较,编写测试:
@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)));
}
匹配器将基于自定义的 compareTo
逻辑工作。
5. NaN 匹配器
Hamcrest 提供额外匹配器检测非数字值:
@Test
public void givenNaN_whenIsNotANumber_thenCorrect() {
double zero = 0d;
assertThat(zero / zero, is(notANumber()));
}
6. 总结
数字匹配器极大简化了常见断言场景。
Hamcrest 匹配器整体具有自解释性和高可读性,
结合自定义比较逻辑的能力,使其成为大多数项目的强大工具。
本文完整示例代码可在 GitHub 获取。