1. 概述
最近在翻阅 Spring 源码的时候,发现它引入了一个新的框架来进行单元测试——Hamcrest 。查阅相关的资料学习了一下,发现确实是一个非常简洁高效的测试框架,它捆绑在JUnit中。
记录一下探索Hamcrest API并学习的过程,让更多的人了解到这种直观的单元测试。
2. Hamcrest依赖
我们可以通过在pom.xml文件中添加以下依赖项来将Hamcrest与maven一起使用:
1 | <dependency> |
可以在此处找到此库的最新版本。
3. Demo
Hamcrest通常与junit和其他测试框架一起用于进行断言。具体来说,我们只使用API的单个assertThat语句与适当的匹配器,而不是使用junit的众多assert方法。
让我们看一个测试两个 String 的相似性的例子,以便清楚地了解Hamcrest如何进行测试:
1 | public class StringMatcherTest { |
在接下来的部分中,我们将介绍Hamcrest提供的其他几个常见匹配器。
4. Class 匹配器
Hamcrest提供了用于在任意Java对象上进行断言的匹配器。
断言 Object 的 toString 方法返回指定的 String :
1 |
|
我们还可以检查一个类是另一个类的子类:
1 |
|
5. bean 匹配器
我们可以使用Hamcrest的Bean匹配器来检查Java bean的属性。
假设以下 Person bean:
1 | public class Person { |
我们可以检查bean是否具有name 属性:
1 |
|
我们还可以检查 Person 是否具有地址属性,并且值为纽约:
1 |
|
我们还可以检查是否使用相同的值构造了两个 Person 对象:
1 |
|
6. Collection 匹配器
Hamcrest提供用于检查Collection 的匹配器。
简单检查一下Collection是否为空:
1 |
|
要检查Collection 的大小:
1 |
|
当然,对于数组也有类似的方法:
1 |
|
检查Collection是否包含给定成员(无论顺序如何):
1 |
|
进一步断言Collection 成员(按给定顺序排列):
1 |
|
要检查数组是否包含给定元素:
1 |
|
我们也可以反过来,测试某个元素是否存在于某个 Collection 中:
1 |
|
另外一个相似的 API 如下:
1 |
|
类似的,对于数组也有这样的 API,检查数组是否包含某个元素(顺序无关):
1 |
|
要检查数组是否包含给定元素但是按给定顺序:
1 |
|
如果是 Map ,可以使用以下匹配器:
要检查它是否包含给定的 key:
1 |
|
和给定的 value:
1 |
|
检查 Entry :
1 |
|
7. Number 匹配器
该Numerb 匹配器是用来对变量进行数字相关的断言。
要检查 greatThen 条件:
1 |
|
检查 greaterThan 或 equalTo 条件:
1 |
|
检查 lessThan 条件:
1 |
|
检查 lessThan 或 equalTo 条件:
1 |
|
要检查 closeTo 条件:
1 |
|
这个检查方法特别的有意思,但是个人认为适用的场景并不是很多,它是用来测试 某个数字是否约等于基准值(第二个参数为误差范围)
8. Text 匹配器
使用Hamcrest的文本匹配器,对String的断言变得更容易,更整洁,更直观。
要检查 String 是否为空:
1 |
|
要检查 String 是空还是 null :
1 |
|
检查两个String的是否相等(忽略空格):
1 |
|
我们还可以检查给定顺序中给定 String 中是否存在一个或多个子字符串:
1 |
|
检查两个 String 是否相等(忽略大小写):
1 |
|
9. 核心API
虽然 Hamcrest 核心API是通过第三方框架提供的。但是,它为我们提供了一些很好的结构,使我们的单元测试更具可读性,还有一些可以轻松使用的核心匹配器。
9.1 is
1 |
|
9.2 not
1 |
|
9.3 String
检查String是否包含给定的子字符串:
1 |
|
检查String是否以给定的子字符串开头:
1 | public void givenAString_whenStartsWithAnotherGivenString_thenCorrect() { |
检查String是否以给定的子字符串结尾:
1 |
|
9.4 Object
检查两个Object是否属于同一个实例:
1 |
|
检查Object是否是给定类的实例:
1 |
|
9.5 Collection
1 |
|
9.6 断言链
anyOf:当目标满足任何条件时测试通过,类似于逻辑OR:
1 |
|
allOf:只有在目标满足所有条件时才通过测试,类似于逻辑AND:
1 |
|
10.自定义匹配器
我们可以通过扩展TypeSafeMatcher来定义我们自己的匹配器。比如,我们将创建一个自定义匹配器,只有当目标是正整数时才允许测试通过。
1 | public class IsPositiveInteger extends TypeSafeMatcher<Integer> { |
我们只需要实现 matchSafely 方法来检查目标是否确实是一个正整数,而 describeTo 方法在测试未通过的情况下产生失败消息。
测试:
1 |
|
如果我们验证一个负数,错误信息将如下所示:
1 | java.lang.AssertionError: Expected: a positive integer but: was <-1> |