1. 简介
Hamcrest是Java中用于编写匹配器对象的流行框架,提供了一种表达性强的条件匹配方式。其中hasItems()
、contains()
和containsInAnyOrder()
这些匹配器,让我们能断言集合中元素的存在性和顺序性。本文将深入剖析每个匹配器的功能、差异及适用场景。
2. 元素顺序处理
本节探讨三个匹配器对集合元素顺序的不同要求。
2.1. hasItems()
hasItems()
匹配器只检查集合是否包含特定元素,完全无视元素顺序:
List<String> myList = Arrays.asList("apple", "banana", "cherry");
assertThat(myList, hasItems("apple", "cherry", "banana"));
assertThat(myList, hasItems("banana", "apple", "cherry"));
2.2. containsInAnyOrder()
与hasItems()
类似,containsInAnyOrder()
同样忽略元素顺序。它只关心指定元素是否全部存在,顺序无所谓:
assertThat(myList, containsInAnyOrder("apple", "cherry", "banana"));
assertThat(myList, containsInAnyOrder("banana", "apple", "cherry"));
2.3. contains()
contains()
匹配器则对顺序敏感。它要求集合必须按指定顺序精确包含所有元素:
assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("banana", "apple", "cherry")));
第一个断言通过,因为元素顺序完全匹配。第二个断言使用not()
匹配器,验证myList
不包含乱序元素。
3. 元素数量要求
本节分析三个匹配器对集合元素数量的处理方式。
3.1. hasItems()
hasItems()
不要求集合元素数量完全匹配。它只关注指定元素是否存在,对集合大小和顺序无严格要求:
assertThat(myList, hasItems("apple", "banana"));
assertThat(myList, hasItems("apple", "banana", "cherry"));
assertThat(myList, not(hasItems("apple", "banana", "cherry", "date")));
✅ 前两个断言通过,因为所有指定元素都存在
❌ 第三个断言通过,因为集合中不存在"date"元素
⚠️ 注意:当集合包含未指定的额外元素时,断言会失败
3.2. containsInAnyOrder()
与hasItems()
不同,containsInAnyOrder()
要求集合必须包含所有指定元素。顺序无关紧要,但元素必须完全匹配:
assertThat(myList, containsInAnyOrder("apple", "banana", "cherry"));
assertThat(myList, not(containsInAnyOrder("apple", "banana")));
✅ 第一个断言通过,所有元素都存在
❌ 第二个断言通过,因为缺少"cherry"元素
3.3. contains()
与containsInAnyOrder()
类似,contains()
也要求元素数量完全匹配,但必须严格按指定顺序:
assertThat(myList, contains("apple", "banana", "cherry"));
assertThat(myList, not(contains("apple", "banana")));
✅ 第一个断言通过,顺序和数量都匹配
❌ 第二个断言通过,因为缺少"cherry"元素
4. 重复元素处理
当集合包含重复元素时,三个匹配器的行为差异明显。
4.1. hasItems()
hasItems()
完全忽略重复元素。它只检查指定元素是否存在,不关心出现次数:
List<String> myListWithDuplicate = Arrays.asList("apple", "banana", "cherry", "apple");
assertThat(myListWithDuplicate, hasItems("apple", "banana", "cherry"));
✅ 断言通过,即使"apple"重复出现
4.2. containsInAnyOrder()
containsInAnyOrder()
要求元素数量精确匹配,包括重复元素:
assertThat(myList, containsInAnyOrder("apple", "banana", "cherry", "apple"));
assertThat(myListWithDuplicate, not(containsInAnyOrder("apple", "banana", "cherry")));
❌ 第一个断言失败,因为myList
没有重复的"apple"
❌ 第二个断言通过,因为测试数据缺少重复的"apple"
4.3. contains()
contains()
要求元素序列和数量完全匹配,包括重复元素:
assertThat(myList, not(contains("apple", "banana", "cherry")));
❌ 断言通过,因为myList
没有重复的"apple"元素
5. 总结
下表清晰对比了三个匹配器的核心差异:
匹配器 | 顺序敏感 | 精确数量 | 重复元素处理 | 主要用途 |
---|---|---|---|---|
hasItems() |
❌ 否 | ❌ 否 | 忽略重复 | 检查元素是否存在,顺序无关 |
containsInAnyOrder() |
❌ 否 | ✅ 是 | 要求精确匹配 | 检查所有元素是否存在,顺序无关 |
contains() |
✅ 是 | ✅ 是 | 要求精确匹配 | 检查元素序列和数量是否完全一致 |
6. 结论
本文详细分析了Hamcrest中三个常用匹配器的区别:
- 当只关心集合是否包含指定元素(顺序无关)时,使用
hasItems()
- 当必须包含所有指定元素但顺序无关时,使用
containsInAnyOrder()
- 当必须严格按指定顺序包含所有元素时,使用
contains()
简单粗暴的选择原则:
✅ 元素存在性检查 → hasItems()
✅ 元素完整性检查 → containsInAnyOrder()
✅ 元素序列检查 → contains()
所有示例代码已上传至GitHub仓库,欢迎参考实践。