断言框架:Hamcrest
Hamcrest 介绍
-
Hamcrest(官网)是一个以测试为目的,能组合灵活表达式的匹配器类库,主要用于编写断言的框架。它可以与 JUnit 框架配合使用,使断言可读更高、更加灵活(例如判断数组、集合、Map 中的内容等)。
-
Hamcrest 提供了大量被称为“匹配器”的方法。每个匹配器都设计用于执行特定的比较操作。
-
Hamcrest 的可扩展性强,能够创建自定义的匹配器。
-
支持多种语言:Java、Python、Ruby、Object-C、Php、Erlang、Swift 等,本文以使用 JAVA 为例。
Hamcrest 常用匹配器
Maven 依赖:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
字符串匹配器
方法名 | 用法 | 说明 |
---|---|---|
equalTo | assertThat(testedValue, equalTo(expectedValue)); | 断言被测的 testedValue 是否等于 expectedValue。equalTo 可用于断言数值之间、字符串之间、对象之间的比较,相当于 Object 的 equals 方法 |
equalToIgnoringCase | assertThat(testedString, equalToIgnoringCase(expectedString)); | 断言被测的字符串 testedString 在忽略大小写的情况下等于 expectedString |
equalToIgnoringWhiteSpace | assertThat(testedString, equalToIgnoringWhiteSpace(expectedString); | 断言被测的字符串 testedString 在忽略头尾的任意个空格的情况下等于 expectedString |
containsString | assertThat(testedString, containsString(subString)); | 断言被测的字符串 testedString 包含子字符串 subString |
endsWith | assertThat(testedString, endsWith(suffix)); | 断言被测的字符串 testedString 以子字符串 suffix 结尾 |
startsWith | assertThat(testedString, startsWith(prefix)); | 断言被测的字符串 testedString 以子字符串 prefix 开始 |
anything | assertThat("随便是个啥", anything("总是匹配就完事了")); | 总是匹配 |
数值匹配器
方法名 | 用法 | 说明 |
---|---|---|
closeTo | assertThat(testedDouble, closeTo(20.0, 0.5)); | 断言被测的浮点型数testedDouble在 20.0-0.5 ~ 20.0+0.5 范围之内 |
greaterThan | assertThat(testedNumber, greaterThan(16.0)); | 断言被测的数值 testedNumber 大于 16.0 |
lessThan | assertThat(testedNumber, lessThan(16.0)); | 断言被测的数值 testedNumber 小于 16.0 |
greaterThanOrEqualTo | assertThat(testedNumber, greaterThanOrEqualTo (16.0)); | 断言被测的数值 testedNumber 大于等于 16.0 |
lessThanOrEqualTo | assertThat(testedNumber, lessThanOrEqualTo(16.0)); | 断言被测的 testedNumber 小于等于 16.0 |
集合匹配器
方法名 | 用法 | 说明 |
---|---|---|
hasEntry | assertThat(mapObject, hasEntry("key", "value" )); | 断言被测的 Map 对象 mapObject 含有一个键值为 "key" 对应元素值为 "value" 的 Entry 项 |
hasItem | assertThat(iterableObject, hasItem(element)); | 表明被测的迭代对象 iterableObject 含有元素 element 项则测试通过 |
hasKey | assertThat(mapObject, hasKey("key")); | 断言被测的 Map 对象 mapObject 含有键值 "key" |
hasValue | assertThat(mapObject, hasValue(value)); | 断言被测的 Map 对象 mapObject 含有元素值 value |
对象匹配器
方法名 | 用法 | 说明 |
---|---|---|
hasToString | assertThat(true, hasToString(equalTo("true"))); | 断言被测对象的 toString 方法结果等于 "true" |
instanceOf | assertThat("string", instanceOf(String.class)); | 断言被测对象属于字符串类 |
typeCompatibleWith | assertThat(Integer.class, typeCompatibleWith(Number.class)); | 断言 Integer 类兼容 Number 类 |
sameInstance | Integer number = new Integer(200); assertThat(number, sameInstance(number)); |
断言被测对象与 number 对象属于同一实例 |
hasProperty | assertThat(new MyClass(), hasProperty("name")); | 断言被测对象含有 name 属性 |
逻辑匹配器
方法名 | 用法 | 说明 |
---|---|---|
nullValue | assertThat(object, nullValue()); | 断言被测 object 的值为 null |
notNullValue | assertThat(object, notNullValue()); | 断言被测 object 的值不为 null |
is | assertThat(testedString, is(equalTo(expectedValue))); | 断言被测的 object 等于后面给出匹配表达式 |
is 匹配符简写应用之一 | assertThat(testedValue, is(expectedValue)); | is(equalTo(x)) 的简写,断言 testedValue 等于 expectedValue |
is 匹配符简写应用之二 | assertThat(testedObject, is(Cheddar.class)); | is(instanceOf(SomeClass.class)) 的简写,断言 testedObject 为 Cheddar 的实例 |
not | assertThat(testedString, not(expectedString)); | 与 is 匹配符正好相反,断言被测的 object 不等于后面给出的 object |
allOf | assertThat(testedNumber, allOf(greaterThan(8), lessThan(16))); | 断言符合所有条件,相当于 "与"(&&) |
anyOf | assertThat(testedNumber, anyOf(greaterThan(16), lessThan(8))); | 断言符合条件之一,相当于 "或"(||) |
自定义匹配器
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
/**
* 自定义匹配器,判断年龄范围在 [1,200] 返回 true
* 1、继承 TypeSafeMatcher 并指定泛型
* 2、重写 matchesSafely、describeTo 方法
* 3、提供外部调用的静态方法
*/
public class IsNormalAgeRange extends TypeSafeMatcher<Integer> {
@Override
public boolean matchesSafely(Integer number) {
return number >=1 && number <= 200;
}
@Override
public void describeTo(Description description) {
description.appendText("need to be within [1, 200]");
}
public static Matcher normalAgeRange() {
return new IsNormalAgeRange();
}
}
测试:
@Test
public void testMyMatcher() {
assertThat(100, IsNormalAgeRange.normalAgeRange());
}