Hamcrest简介
Hamcrest首先出现于Java语言,目前支持以下编程语言:Java, Python, Ruby, Objective-C, PHP, Erlang, Swift。
Hamcrest不是测试框架,只是一个比较器(matcher),判断某个结果是否和预期的一样。目前比较器进化有三个阶段:
- assert(logical statement),判断一个布尔表达式是否为true,例如Java本身的,assert a == b : “a is different with b“;
- assertEquals(expected, actual),判断实际数据和预期的是否一致,因为数据类型的不同,产生了很多重载方法;
- assertThat(actual, matcher expression),这是Hamcrest的格式,第一个参数是实际数据,第二个参数是比较表达式。
Hamcrest的初衷是提高unit test的可读性,进而提高unit test的可维护性,并且Hamcrest比较失败时的message可读性更好。
最新版本是1.4-atlassian-1,但用的最多的是1.3,下面是Maven中的下载坐标:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
</dependency>
P.S.
Junit从4.4版本开始,就引入了Hamcrest的核心比较器(hamcrest-core-{version}.jar),可以不用单独引入Hamcrest,但是核心比较器包含的matcher不是很多,最好还是单独引入一个Hamrcrest。
Hamcrest使用总结
hamcrest的比较格式:assertThat(actual, {expected matcher expression});
1. 字符串比较
1.1 equalTo
判断字符串是否相等。
String name = "Hello"; assertThat(name, equalTo("Hello"));
1.2 equalToIgnoringCase
比较时,忽略字符串大小写。
String name = "HELLO"; assertThat(name, equalToIgnoringCase("hello"));
1.3 equalToIgnoringWhiteSpace
去掉actual string和expected string的前后whitspace,字符串中间多个whitspace变成一个whitespace,然后比较是否相等。
String name = " he llo "; assertThat(name, equalToIgnoringWhiteSpace(" he llo "));
1.4 containsString
判断是否包含某个字符串。
String name = "Hello the world"; assertThat(name, containsString("the"));
1.5 startsWith, endsWith
判断是否以某个字符串开头或结尾。
String name = "Hello the world"; assertThat(name, startsWith("Hello")); assertThat(name, endsWith("world"));
1.6 isEmptyString, isEmptyOrNullString
判断字符串是否为空或null。
String name = "Hello the world"; assertThat(name, isEmptyString()); assertThat(name, isEmptyOrNullString());
2. 数值比较(byte, int, long, float, double)
2.1 比较数值相等
hamcrest将原子值封装成对象(int –> Integer),然后调用对象的euqals方法。浮点数不能控制比较精度,需要控制精度,就用assertEquals(d1, d2, delta)。
double price = 11.23; assertThat(price, equalTo(11.23));
P.S.
下面关于数值的比较,hamcrest将其封装成对象(int –> Integer),然后调用对象的compareTo方法,所以就算不是数值类型,只要其实现了Comparable接口,也可以进行比较。
2.2 greaterThan, lessThan
判断是否大于或小于某个数。
double price = 11.23; assertThat(price, greaterThan(10.01)); assertThat(price, lessThan(13.22));
2.3 greaterThanOrEqualTo, lessThanOrEqualTo
判断是否大于等于或者小于等于某个数。
double price = 11.23; assertThat(price, greaterThanOrEqualTo(10.01)); assertThat(price, lessThanOrEqualTo(13.22));
3. 布尔值比较
使用equalTo,个人感觉这个不如Junit的assertTrue和assertFalse好。
boolean isLocked = true; assertThat(isLocked, equalTo(true)); // Junit way of checking boolean assertTrue(isLocked); assertFalse(isLocked);
4. 对象比较
4.1 euqalTo
调用对象的equals方法比较,actual object 和 expceted object可以是null,仅当它们都是null时,才会比较成功。两者如果只有一个是null,会抛出null pointer exception。
Person p1 = new Person("Monday"); Person p2 = new Person("Monday"); assertThat(p1, equalTo(p2)); // pass assertThat(null, equalTo(null)); // pass // Below two case throw null pointer exception. assertThat(p1, equalTo(null)); assertThat(null, equalTo(p1));
4.2 sameInstance
比较是否是同一个对象。
assertThat(person1, sameInstance(person2));
4.3 instanceOf
判断是否是某个类的实例。
String str = "hello"; assertThat(str, instanceOf(String.class));
4.4 nullValue, notNullValue
判断一个对象是否为null。
assertThat(obj, nullValue()); assertThat(obj, notNullValue());
5. 数组比较
5.1 equalTo,arrayContaining
它俩效果一样,当两个数组长度相等,且按顺序每个元素相同时,他们相等。
Integer[] nums = {1, 2, 3}; assertThat(nums, equalTo(new int[] {1, 2, 3})); assertThat(nums, arrayContaining(1, 2, 3));
5.2 arrayWithSize
判断数组大小。
assertThat(nums, arrayWithSize(3));
5.3 arrayContainingInAnyOrder
两数组,长度相同,不考虑顺序,它们包含相同的元素,则断言为true。
Integer[] nums = {1, 2, 3}; assertThat(nums, arrayContainingInAnyOrder(2, 1, 3));
6. Map比较
hasEntry判断是否包含某个<key, value>,hasKey判断是否包含某个key,hasValue判断是否包含某个value。
Map<String, Integer> map = Maps.newHashMap(); assertThat(map, hasEntry("key", "value")); assertThat(map, hasKey("key")); assertThat(map, hasValue("value"));
7. Collection比较
常用的Collection有List和Set。下面的例子,是对List<String> list = List.newArrayList(1, 2, 3),做的操作,Set操作一样。
7.1 hasSize
判断集合的大小。
assertThat(list, hasSize(3));
7.2 hasItem, hasItems
判断是否包含指定的一个元素或多个元素。
List<Integer> list = Lists.newArrayList(1, 2, 3); assertThat(list, hasItem(2)); assertThat(list, hasItems(3, 3, 2));
hasItem嵌套anyOf或allOf,可以对元素指定多个判断条件。
List<String> strs = Lists.newArrayList(); assertThat(strs, hasItem(anyOf(equalTo("Alex"), equalTo("alzhang")))); assertThat(strs, hasItem(allOf(startsWith("a"), endsWith("g"))));
7.3 contains
两个List的size相同,并且按顺序,每个元素相等。
List<Integer> list = Lists.newArrayList(1, 2, 3); assertThat(list, contains(1, 2, 3));
7.4 containsInAnyOrder
两个List的size相同,不考虑顺序,他们包含相同的元素。
List<Integer> list = Lists.newArrayList(1, 2, 3); assertThat(list, containsInAnyOrder(2, 3, 1));
7.5 everyItem
对集合的每个元素,进行match,只有都match了,断言才为true。
List<Integer> list = Lists.newArrayList(1, 2, 3); assertThat(list, everyItem(greaterThan(0)));
注:我本以为有anyItem方法,只要有一个match了,断言就为true,但是我没找到该方法。
8. Bean对象比较
Bean就是数据对象,包含大量的getter/setter方法。
8.1 hasProperty
判断Bean是否有某个类变量,该变量至少有一个get方法或set方法,否则Hamcrest不认为其是个property。
assertThat(person, hasProperty("name")); assertThat(person, hasProperty("name", equalTo("abcd")));
8.2 samePropertyValuesAs
判断两个Bean是否有相同的Property,并且它们的Value也相等。
class Flight { String id; String country; String speed; // Getters, Settes. } assertThat(flight1, samePropertyValuesAs(flight2))
9. 与或非,逻辑组合
9.1 allOf
对一个元素的判断,需要同时成立。
int width = 13; assertThat(width, allOf(greaterThan(10), lessThanOrEqualTo(13))); assertThat(person, allOf(hasProperty("name"), hasProperty("gender")));
9.2 anyOf
对一个元素的判断,只要有一个成立。
assertThat(width, anyOf(equalTo(0), greaterThan(100))); assertThat(person.getName(), anyOf(equalTo("Hillary"), equalTo("Trump")));
9.3 not
对一个判断取反。
assertThat(list, not(hasItem(2))); assertThat(str, not(startsWith("http")));
10. 自定义Matcher
针对某些特殊的比较,可以写自己的matcher。下面的例子,写了一个matcher,用于判断一个Session是否Done(运行结束)。
class SessionMatcher extends TypeSafeMatcher<Session> { @Override public void describeTo(Description description) { // Describe what this matcher expects. description.appendText("Session status shall be done " + "and session result shall be generated."); } @Override protected boolean matchesSafely(Session session) { return "done".equals(session.getStatus()) && session.hasResult(); } } Session session = new Session(); assertThat(session, new SessionMatcher());
11. 其它
11.1 is
可以用来包裹任何matcher,提高可读性,可有可无,看个人喜好。
String str = "hello"; assertThat(str, is(equalTo("Hello"))); assertThat(str, is(startsWith("h"))); assertThat(str, is(instanceOf(String.class)));