1. 引言
JUnit4提供的新斷言語法具有很多優點且使用簡單,這已經不再是新鮮事了,可發現在實際測試代碼中仍未被普及應用,特發此文,以期更多的人能掌握運用。
2. assertThat基本語法
Hamcrest 是一個測試輔助工具,提供了一套通用的匹配符 Matcher,靈活使用這些匹配符定義的規則,程序員可以更加精確的表達自己的測試思想,指定所想設定的測試條件。
Junit4結合Hamcrest提供了新的斷言語句-assertThat,只需一個assertThat語句,結合Hamcrest提供的匹配符,就可以表達全部的測試思想。
assertThat的基本語法如下:
assertThat(T actual, Matcher matcher)
assertThat(String reason, T actual, Matcher matcher)
actual 是接下來想要驗證的值;
matcher是使用 Hamcrest 匹配符來表達的對前面變量所期望的值的聲明,如果 actual值與 matcher 所表達的期望值相符,則斷言成功,否則斷言失敗。
reason是自定義的斷言失敗時顯示的信息。
一個簡單的例子:
// 如果測試的字符串testedString包含子字符串"taobao"則斷言成功
assertThat( testedString, containsString( "taobao" ) );
3. assertThat優點
- 統一
只需一條assertThat語句即可替代舊有的其他語句(如 assertEquals,assertNotSame,assertFalse,assertTrue,assertNotNull,assertNull 等),使斷言變得簡單、代碼風格統一,增強測試代碼的可讀性和可維護性。
?
- 語法直觀易懂
assertThat 不再像 assertEquals 那樣,使用比較難懂的“謂賓主”語法模式(如:assertEquals(3, x);)。相反,assertThat 使用了類似于“主謂賓”的易讀語法模式(如:assertThat(x,is(3));),使得代碼更加直觀、易讀,符合人類思維習慣。
?
- 錯誤信息更具描述性
舊的斷言語法如果斷言失敗,默認不會有額外的提示信息,如
assertTrue(testedString.indexOf(“taobao”) > -1);
如果該斷言失敗,只會拋出無用的錯誤信息,如java.lang.AssertionError: ,除此之外不會有更多的提示信息。
新的斷言語法會默認自動提供一些可讀的描述信息,如
assertThat(testedString, containsString(“taobao”));
如果該斷言失敗,拋出的錯誤提示信息如下:
java.lang.AssertionError:
Expected: a string containing “taobao”
got: “taoba”
?
- 跟Matcher匹配符聯合使用更靈活強大
Matcher提供了功能豐富的匹配符,assertThat結合這些匹配符使用可更靈活更準確的表達測試思想。
// 驗證字符串 s是否含有子字符串 "taobao" 或 "qa" 中間的一個
// 舊的斷言,不直觀,需要分析代碼邏輯明白驗證意圖
assertTrue(s.indexOf("taobao")>-1||s.indexOf("qa")>-1);
// 新的斷言,直觀易懂,準確表達測試思想
assertThat(s,anyOf(containsString("taobao"),containsString("qa")));
// anyOf滿足條件之一即成立,containsString包含字符串則成立
4. assertThat使用
要想發揮assetThat的威力,必須跟Hamcrest聯合使用,JUnit4本身包含了一些自帶了一些 Hamcrest 的匹配符 Matcher,但是只有有限的幾個。因此建議你將Hamcrest包加入項目。
在pom里加入Hamcrest依賴。
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
</dependency>
在測試類里導入包
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
通過例子學習是有效的學習方式之一,下面通過常用的示例演示如何使用assertThat,更詳細的用法請參考Hamcrest相關文檔。
- 字符相關匹配符
/**equalTo匹配符斷言被測的testedValue等于expectedValue,
* equalTo可以斷言數值之間,字符串之間和對象之間是否相等,相當于Object的equals方法
*/
assertThat(testedValue, equalTo(expectedValue));
/**equalToIgnoringCase匹配符斷言被測的字符串testedString
*在忽略大小寫的情況下等于expectedString
*/
assertThat(testedString, equalToIgnoringCase(expectedString));
/**equalToIgnoringWhiteSpace匹配符斷言被測的字符串testedString
*在忽略頭尾的任意個空格的情況下等于expectedString,
*注意:字符串中的空格不能被忽略
*/
assertThat(testedString, equalToIgnoringWhiteSpace(expectedString);
/**containsString匹配符斷言被測的字符串testedString包含子字符串subString**/
assertThat(testedString, containsString(subString) );
/**endsWith匹配符斷言被測的字符串testedString以子字符串suffix結尾*/
assertThat(testedString, endsWith(suffix));
/**startsWith匹配符斷言被測的字符串testedString以子字符串prefix開始*/
assertThat(testedString, startsWith(prefix));
- 一般匹配符
/**nullValue()匹配符斷言被測object的值為null*/
assertThat(object,nullValue());
/**notNullValue()匹配符斷言被測object的值不為null*/
assertThat(object,notNullValue());
/**is匹配符斷言被測的object等于后面給出匹配表達式*/
assertThat(testedString, is(equalTo(expectedValue)));
/**is匹配符簡寫應用之一,is(equalTo(x))的簡寫,斷言testedValue等于expectedValue*/
assertThat(testedValue, is(expectedValue));
/**is匹配符簡寫應用之二,is(instanceOf(SomeClass.class))的簡寫,
*斷言testedObject為Cheddar的實例
*/
assertThat(testedObject, is(Cheddar.class));
/**not匹配符和is匹配符正好相反,斷言被測的object不等于后面給出的object*/
assertThat(testedString, not(expectedString));
/**allOf匹配符斷言符合所有條件,相當于“與”(&&)*/
assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );
/**anyOf匹配符斷言符合條件之一,相當于“或”(||)*/
assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
- 數值相關匹配符
/**closeTo匹配符斷言被測的浮點型數testedDouble在20.0¡À0.5范圍之內*/
assertThat(testedDouble, closeTo( 20.0, 0.5 ));
/**greaterThan匹配符斷言被測的數值testedNumber大于16.0*/
assertThat(testedNumber, greaterThan(16.0));
/** lessThan匹配符斷言被測的數值testedNumber小于16.0*/
assertThat(testedNumber, lessThan (16.0));
/** greaterThanOrEqualTo匹配符斷言被測的數值testedNumber大于等于16.0*/
assertThat(testedNumber, greaterThanOrEqualTo (16.0));
/** lessThanOrEqualTo匹配符斷言被測的testedNumber小于等于16.0*/
assertThat(testedNumber, lessThanOrEqualTo (16.0));
- 集合相關匹配符
/**hasEntry匹配符斷言被測的Map對象mapObject含有一個鍵值為"key"對應元素值為"value"的Entry項*/
assertThat(mapObject, hasEntry("key", "value" ) );
/**hasItem匹配符表明被測的迭代對象iterableObject含有元素element項則測試通過*/
assertThat(iterableObject, hasItem (element));
/** hasKey匹配符斷言被測的Map對象mapObject含有鍵值“key”*/
assertThat(mapObject, hasKey ("key"));
/** hasValue匹配符斷言被測的Map對象mapObject含有元素值value*/
assertThat(mapObject, hasValue(value));
轉載務必注明出處Taobao QA Team,原文地址:http://qa.taobao.com/?p=3541