此断言语法的优点包括:更具可读性和可键入性。
JUnit中的部分断言的可读性并不是很好,有时我们不得不自己编写表达式并断言其结果,并且因为我们没有提供失败的信息,当这个断言失败时只会抛出java.lang.AssertionError
,无法知道到底是哪一部分出错。
assertTrue(responseString.contains("color") || responseString.contains("colour"));
// ==> failure message:
// java.lang.AssertionError:
assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
// ==> failure message:
// java.lang.AssertionError:
// Expected: (a string containing "color" or a string containing "colour")
// but: was "responseString字符串"
JUnit4.4
引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活。并且使用全新的断言语法:assertThat
,结合Hamcest提供的匹配符,只用这一个方法,就可以实现所有的测试。
assertThat
语法如下:
其中reason
为断言失败时的输出信息,actual
为断言的值或对象,matcher
为断言的匹配器,里面的逻辑决定了给定的actual
对象满不满足断言。
JUnit4的匹配器定义在org.hamcrest.CoreMatchers
和 org.junit.matchers.JUnitMatchers
中。通过静态导入的方式引入相应的匹配器,如下:
import static org.hamcrest.CoreMatchers.is;
或者:
import static org.hamcrest.CoreMatchers.*;
org.junit.matchers.JUnitMatchers比较器中大部分都被标记为Deprecated,并使用org.hamcrest.CoreMatchers
对应方法进行取代,但有两个方法得到了保留:
isException
(MatcherisThrowable
MatcherHamcrest CoreMatchers
在JUnit4.9版本被包含在JUnit的分发包中。
Hamcrest comes with a library of useful matchers. Here are some of the most important ones.
Hamcrest提供了一个有用的匹配库。以下是一些最重要的:
anything
- 总是匹配,如果你不关心测试下的对象是什么是有用的describedAs
- 添加一个定制的失败表述装饰器is
- 改进可读性装饰器 - 见下 “Sugar”allOf
- 如果所有匹配器都匹配才匹配(像 Java &&)anyOf
- 如果任何匹配器匹配就匹配 (像 Java ||)not
- 如果包装的匹配器不匹配器时匹配,反之亦然equalTo
- 测试对象相等使用Object.equals方法hasToString
- 测试Object.toString方法instanceOf
, isCompatibleType
- 测试类型notNullValue
, nullValue
- 测试nullsameInstance
- 测试对象实例hasProperty
- 测试JavaBeans属性array
- 测试一个数组元素test an array’s elements against an array of matchershasEntry
, hasKey
, hasValue
- 测试一个Map包含一个实体,键或者值hasItem
, hasItems
- 测试一个集合包含一个元素hasItemInArray
- 测试一个数组包含一个元素closeTo
- 测试浮点值接近给定的值greaterThan
, greaterThanOrEqualTo
, lessThan
, lessThanOrEqualTo
- 测试次序equalToIgnoringCase
- 测试字符串相等忽略大小写equalToIgnoringWhiteSpace
- 测试字符串忽略空白containsString
, endsWith
, startsWith
- 测试字符串匹配示例:
public class C {
public int add(int a, int b) {
return a + b;
}
public double div(double a, double b) {
return a / b;
}
public String getName(String name) {
return name;
}
public List getList(String item) {
List l = new ArrayList();
l.add(item);
return l;
}
public Map getMap(String key, String value) {
Map m = new HashMap();
m.put(key, value);
return m;
}
}
@Test
public void testC() {
// 一般匹配符
int s = new C().add(1, 1);
// allOf:所有条件必须都成立,测试才通过
assertThat(s, allOf(greaterThan(1), lessThan(3)));
// anyOf:只要有一个条件成立,测试就通过
assertThat(s, anyOf(greaterThan(1), lessThan(1)));
// anything:无论什么条件,测试都通过
assertThat(s, anything());
// is:变量的值等于指定值时,测试通过
assertThat(s, is(2));
// not:和is相反,变量的值不等于指定值时,测试通过
assertThat(s, not(1));
// 数值匹配符
double d = new C().div(10, 3);
// closeTo:浮点型变量的值在3.0±0.5范围内,测试通过
assertThat(d, closeTo(3.0, 0.5));
// greaterThan:变量的值大于指定值时,测试通过
assertThat(d, greaterThan(3.0));
// lessThan:变量的值小于指定值时,测试通过
assertThat(d, lessThan(3.5));
// greaterThanOrEuqalTo:变量的值大于等于指定值时,测试通过
assertThat(d, greaterThanOrEqualTo(3.3));
// lessThanOrEqualTo:变量的值小于等于指定值时,测试通过
assertThat(d, lessThanOrEqualTo(3.4));
// 字符串匹配符
String n = new C().getName("Magci");
// containsString:字符串变量中包含指定字符串时,测试通过
assertThat(n, containsString("ci"));
// startsWith:字符串变量以指定字符串开头时,测试通过
assertThat(n, startsWith("Ma"));
// endsWith:字符串变量以指定字符串结尾时,测试通过
assertThat(n, endsWith("i"));
// euqalTo:字符串变量等于指定字符串时,测试通过
assertThat(n, equalTo("Magci"));
// equalToIgnoringCase:字符串变量在忽略大小写的情况下等于指定字符串时,测试通过
assertThat(n, equalToIgnoringCase("magci"));
// equalToIgnoringWhiteSpace:字符串变量在忽略头尾任意空格的情况下等于指定字符串时,测试通过
assertThat(n, equalToIgnoringWhiteSpace(" Magci "));
// 集合匹配符
List l = new C().getList("Magci");
// hasItem:Iterable变量中含有指定元素时,测试通过
assertThat(l, hasItem("Magci"));
Map m = new C().getMap("mgc", "Magci");
// hasEntry:Map变量中含有指定键值对时,测试通过
assertThat(m, hasEntry("mgc", "Magci"));
// hasKey:Map变量中含有指定键时,测试通过
assertThat(m, hasKey("mgc"));
// hasValue:Map变量中含有指定值时,测试通过
assertThat(m, hasValue("Magci"));
}
Other, potentially Matchers out there include