1. 概述
本文带你快速掌握 Hamcrest 框架中 CoreMatchers
类的核心用法。Hamcrest 是 Java 中非常流行的断言库,它的核心理念是让测试断言语句读起来更像自然语言,提升测试代码的可读性。
✅ 举个例子:assertThat(result, is(equalTo("success")))
比传统的 assertEquals("success", result)
更具表达力,逻辑更清晰。
如果你写单元测试还在用一堆 assertTrue
、assertEquals
,那 Hamcrest 真的值得你花点时间了解下,尤其在复杂对象或集合校验时,优势明显。
2. Hamcrest 环境搭建
使用 Maven 的项目,只需在 pom.xml
中引入以下依赖:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
<scope>test</scope>
</dependency>
📌 最新版本可前往 Maven Central 查看。
⚠️ 注意:虽然 JUnit 4 自带部分 Hamcrest 功能,但建议显式引入 java-hamcrest
以获得完整功能支持,避免版本冲突或功能缺失。
3. 常用核心匹配器
3.1 is(T)
与 is(Matcher<T>)
is()
是最常用的“装饰器”方法,它本身不执行判断,而是让语句更自然。
is(T value)
:检查目标是否等于指定值is(Matcher<T>)
:包装另一个 matcher,增强表达力
String testString = "hamcrest core";
assertThat(testString, is("hamcrest core"));
assertThat(testString, is(equalTo("hamcrest core")));
✅ 实际上 is("xxx")
内部就是调用 equalTo("xxx")
,所以两者等价。但 is()
让语句更接近“人话”。
3.2 equalTo(T)
用于判断两个对象是否相等(基于 equals()
方法)。
常与 is()
搭配使用,形成“主谓宾”结构:
String actualString = "equalTo match";
List<String> actualList = Arrays.asList("equalTo", "match");
assertThat(actualString, is(equalTo("equalTo match")));
assertThat(actualList, is(equalTo(Arrays.asList("equalTo", "match"))));
⚠️ 注意:equalTo()
会进行类型检查。如果你希望忽略静态类型(比如 Object 类型对比),可以用:
Object original = 100;
assertThat(original, equalToObject(100)); // 不强制类型一致
但日常使用 equalTo()
足够,类型安全更重要。
3.3 not(T)
与 not(Matcher<T>)
用于否定判断,即“不等于”或“不满足某个条件”。
String testString = "troy kingdom";
assertThat(testString, not("german kingdom"));
assertThat(testString, is(not(equalTo("german kingdom"))));
assertThat(testString, is(not(instanceOf(Integer.class))));
✅ 推荐使用 is(not(...))
风格,语义清晰,可读性强。
3.4 nullValue()
与 nullValue(Class<T>)
判断目标是否为 null
。
Integer nullObject = null;
assertThat(nullObject, is(nullValue()));
assertThat(nullObject, is(nullValue(Integer.class)));
后者可以指定类型,但实际效果与前者基本一致,多用于强调类型上下文。
3.5 notNullValue()
与 notNullValue(Class<T>)
判断目标是否非 null,是 is(not(nullValue()))
的简洁写法。
Integer testNumber = 123;
assertThat(testNumber, is(notNullValue()));
assertThat(testNumber, is(notNullValue(Integer.class)));
✅ 日常断言对象非空时,直接用 notNullValue()
更简洁。
3.6 instanceOf(Class<?>)
判断对象是否是某个类的实例(包括子类),内部调用的是 Class.isInstance()
。
assertThat("instanceOf example", is(instanceOf(String.class)));
⚠️ 注意:它允许继承关系,instanceOf(CharSequence.class)
也能匹配 String
。
3.7 isA(Class<T>)
instanceOf()
的语法糖,功能完全一致,但读起来更像自然语言。
assertThat("Drogon is biggest dragon", isA(String.class));
✅ 推荐在测试中使用 isA
,语句更流畅,比如 isA(List.class)
读作“是一个 List”,很顺。
3.8 sameInstance()
判断两个引用是否指向同一个对象实例(即内存地址相同),基于 ==
比较。
String string1 = "Viseron";
String string2 = string1;
assertThat(string1, is(sameInstance(string2)));
⚠️ 区别于 equalTo()
,sameInstance()
是引用比较,不是值比较。字符串常量池等场景下容易踩坑。
3.9 any(Class<T>)
判断对象是否属于指定类型,常用于泛型匹配或 Mockito 参数捕获。
assertThat("test string", is(any(String.class)));
assertThat("test string", is(any(Object.class)));
✅ 在 mock 测试中非常实用,比如 when(service.process(any(User.class))).thenReturn(...)
。
3.10 allOf()
与 anyOf()
allOf()
:所有条件都必须满足(逻辑与)anyOf()
:满足任意一个条件即可(逻辑或)
String testString = "Achilles is powerful";
assertThat(testString, allOf(
startsWith("Achi"),
endsWith("ul"),
containsString("Achilles")
));
String testString = "Hector killed Achilles";
assertThat(testString, anyOf(
startsWith("Hec"),
containsString("baeldung")
));
✅ 组合断言利器,避免写多个 assertThat
。
3.11 hasItem()
与 hasItems()
用于集合(Iterable
)中是否包含指定元素。
List<String> list = Arrays.asList("java", "spring", "baeldung");
assertThat(list, hasItem("java"));
assertThat(list, hasItem(isA(String.class)));
批量判断多个元素是否存在:
assertThat(list, hasItems("java", "baeldung"));
assertThat(list, hasItems(isA(String.class), endsWith("ing")));
✅ 集合断言中最常用的 matcher 之一,比 assertTrue(list.contains(...))
更优雅。
3.12 both()
与 either()
both().and()
:两个条件都满足either().or()
:满足其一即可
String testString = "daenerys targaryen";
assertThat(testString, both(startsWith("daene")).and(containsString("yen")));
assertThat(testString, either(startsWith("tar")).or(containsString("targaryen")));
✅ 语义清晰,适合简单逻辑组合,比 allOf
/anyOf
更贴近自然语言。
4. 字符串匹配
Hamcrest 提供了丰富的字符串断言工具,支持忽略大小写:
包含判断
String testString = "Rhaegar Targaryen";
assertThat(testString, containsString("aegar"));
assertThat(testString, containsStringIgnoringCase("AEGAR"));
开头判断
assertThat(testString, startsWith("Rhae"));
assertThat(testString, startsWithIgnoringCase("rhae"));
结尾判断
assertThat(testString, endsWith("aryen"));
assertThat(testString, endsWithIgnoringCase("ARYEN"));
✅ 这些 matcher 在校验日志、API 响应、文本处理时非常实用,避免手动 indexOf
或正则。
5. 总结
本文系统梳理了 Hamcrest CoreMatchers
中最常用的核心匹配器,涵盖:
- 基础值比较(
equalTo
,is
,not
) - 空值判断(
nullValue
,notNullValue
) - 类型判断(
instanceOf
,isA
,any
) - 引用比较(
sameInstance
) - 逻辑组合(
allOf
,anyOf
,both
,either
) - 集合与字符串专用 matcher
📌 推荐在项目中逐步引入 Hamcrest,尤其是在复杂的 DTO、集合、条件断言场景下,能显著提升测试代码的可读性和维护性。
所有示例代码已托管至 GitHub:https://github.com/example-java/tutorials/tree/master/testing-modules/hamcrest