1. 引言
Hamcrest 不仅提供内置匹配器,还支持创建自定义匹配器。本文将深入探讨如何创建和使用自定义匹配器。想快速了解现有匹配器?可参考这篇指南。
2. 自定义匹配器环境配置
要使用 Hamcrest,需在 pom.xml
中添加以下 Maven 依赖:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
最新版本可在 Maven Central 查询。
3. 深入理解 TypeSafeMatcher
开始示例前,必须掌握 TypeSafeMatcher
类。创建自定义匹配器时需继承该类。
TypeSafeMatcher
是抽象类,子类必须实现两个方法:
matchesSafely(T t)
:包含核心匹配逻辑describeTo(Description description)
:自定义匹配失败时的提示信息
注意:**TypeSafeMatcher
是泛型类**,使用时需声明类型参数,即待测试对象的类型。下一节的示例将清晰展示这点。
4. 创建 onlyDigits 匹配器
第一个需求:创建匹配器判断字符串是否仅包含数字。例如:
- ✅ "123" → 返回
true
- ❌ "hello1" → 返回
false
- ❌ "bye" → 返回
false
4.1 匹配器实现
创建继承 TypeSafeMatcher
的类:
public class IsOnlyDigits extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String s) {
// 实现逻辑
}
@Override
public void describeTo(Description description) {
// 描述信息
}
}
由于测试对象是字符串,**泛型参数指定为 String
**。完整实现:
public class IsOnlyDigits extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException nfe){
return false;
}
}
@Override
public void describeTo(Description description) {
description.appendText("only digits");
}
}
核心逻辑:尝试将字符串转为整数,成功则返回 true
。describeTo
定义了期望描述。
最后添加静态方法,使其与内置匹配器用法一致:
public static Matcher<String> onlyDigits() {
return new IsOnlyDigits();
}
4.2 匹配器使用
测试用例:
@Test
public void givenAString_whenIsOnlyDigits_thenCorrect() {
String digits = "1234";
assertThat(digits, onlyDigits());
}
测试通过,因为输入仅含数字。为增强可读性,可用 is
包装匹配器:
assertThat(digits, is(onlyDigits()));
若输入 "123ABC",失败信息为:
java.lang.AssertionError:
Expected: only digits
but: was "123ABC"
⚠️ describeTo
的描述直接影响错误信息,务必清晰准确。
5. 创建 divisibleBy 匹配器
需求:判断数字能否被指定数整除。此时需存储参数:
public class IsDivisibleBy extends TypeSafeMatcher<Integer> {
private Integer divider; // 存储除数
public IsDivisibleBy(Integer divider) {
this.divider = divider;
}
@Override
protected boolean matchesSafely(Integer dividend) {
if (divider == 0) return false; // 避免除零
return (dividend % divider) == 0;
}
@Override
public void describeTo(Description description) {
description.appendText("divisible by " + divider);
}
public static Matcher<Integer> divisibleBy(Integer divider) {
return new IsDivisibleBy(divider);
}
}
关键点:通过构造函数传入参数,静态方法暴露接口。测试用例:
@Test
public void givenAnEvenInteger_whenDivisibleByTwo_thenCorrect() {
Integer ten = 10;
assertThat(ten, is(divisibleBy(2)));
}
@Test
public void givenAnOddInteger_whenNotDivisibleByTwo_thenCorrect() {
Integer eleven = 11;
assertThat(eleven, is(not(divisibleBy(2))));
}
简单粗暴,多参数匹配器搞定!
6. 总结
Hamcrest 内置匹配器覆盖了大部分断言场景。当遇到特殊需求时,自定义匹配器是优雅的解决方案——正如本文所示。它们创建简单,用法与内置匹配器完全一致。
完整示例代码见 GitHub 项目。