Java中的異常測(cè)試框架JUnit使用上手指南
JUnit是由 Erich Gamma 和 Kent Beck 編寫(xiě)的一個(gè)回歸測(cè)試框架(regression testing framework)。Junit測(cè)試是程序員測(cè)試,即白盒測(cè)試。該項(xiàng)目主頁(yè):http://www.junit.org/
使用JUnit時(shí),主要都是通過(guò)繼承TestCase類別來(lái)撰寫(xiě)測(cè)試用例,使用testXXX()名稱來(lái)撰寫(xiě)單元測(cè)試。
用JUnit寫(xiě)測(cè)試真正所需要的就三件事:
1. 一個(gè)import語(yǔ)句引入所有junit.framework.*下的類。
2. 一個(gè)extends語(yǔ)句讓你的類從TestCase繼承。
3. 一個(gè)調(diào)用super(string)的構(gòu)造函數(shù)。
功能類MathTool
package com.zj.c01;
public class MathTool {
public static int gcd(int num1, int num2) {
int r = 0;
while (num2 != 0) {
r = num1 % num2;
num1 = num2;
num2 = r;
}
return num1;
}
}
測(cè)試類MathToolTest
package com.zj.c01;
import junit.framework.TestCase;
public class MathToolTest extends TestCase {
public MathToolTest(String name) {
super(name);
}
public void testGcd() {
assertEquals(5, MathTool.gcd(10, 5));
}
}
我們?cè)谟?JUnit 測(cè)試方法異常的時(shí)候,最容易想到的辦法就是用 try…catch 去捕獲異常,需要斷言以下幾個(gè)條件:
1. 確實(shí)拋出的異常
2. 拋出異常的 Class 類型
3. 拋出異常的具體類型,一般檢查異常的 message 屬性中包含的字符串的斷定
所以常用的代碼你可能會(huì)這么寫(xiě):
@Test
public void testBizException()
{
try{
Password.validate( "123" );
fail( "No exception thrown." );
}catch ( Exception ex ) {
assertTrue( ex instanceof BizException );
assertTrue( ex.getMessage().contains( "error" ) );
}
}
這里被測(cè)試的方法是 Password.validate() 方法是否拋出了相應(yīng)的異常,注意這里別漏 try 中的
fail(“No Exception thrown.”)
代碼行,不然如果被測(cè)試的方法如果沒(méi)有拋出異常的話,這個(gè)用例是通過(guò)的,而你預(yù)期的是要拋出異常的。
在 JUnit 4 中,大可不必如此這般的去測(cè)試方法異常。雖然這樣也能測(cè)定出是否執(zhí)行出預(yù)期的異常來(lái),但它仍有弊端,接下來(lái)會(huì)一對(duì)比就知道了,try…catch 的方法,JUnit 無(wú)法為你提示出詳細(xì)的斷言失敗原因。
那么來(lái)看看自從 JUnit 4 后可以怎么去測(cè)試異常呢?用 @Test(execpted=Exception.class) 注解就行,參考如下代碼:
@Test( expected = BizException.class )
public void testBizException()
{
Password.validate( null );
}
如果被測(cè)試的方法有拋出 BizException類型便是斷言成功,對(duì)了 @Test(expected = BizException.class) 只能判斷出異常的類型,并無(wú)相應(yīng)的注解能斷言出異常的更具體的信息,即無(wú)法判定拋出異常的 message 屬性。
那么,有時(shí)候我們會(huì)在一個(gè)方法中多次拋出一種類型的異常,但原因不同,即異常的 message 信息不同,比如出現(xiàn) BizException 時(shí)會(huì)有以下兩種異常:
new BizException(“Password must contains at least 6 letters.”) new BizException(“Password length less than 15 letters”)
這就要有辦法去斷言異常的 message 了,針對(duì)于此,自 JUnit 4.7 之后又給了我們更完美的選擇,就是下面的代碼:
@Rule
public ExpectedException expectedEx = ExpectedException.none();
@Test
public void testBizException() throws InvalidPasswordException
{
expectedEx.expect( BizException.class );
expectedEx.expectMessage( "required" );
Password.validate( "" );
}
上面代碼需重點(diǎn)關(guān)注幾個(gè):
1. @Rule 注解的 ExpectedException 變量聲明,它必須為 public
2. @Test 處,不能寫(xiě)成 @Test(expected=BizException.class),否則不能正確測(cè)試,也就是
@Test(expected=BizException.class) 和測(cè)試方法中的 expectedEx.expectXxx() 方法是不能同時(shí)并存的
3. expectedEx.expectMessage() 中的參數(shù)是 Matcher 或 subString,就是說(shuō)可用正則表達(dá)式判定,或判斷是否包含某個(gè)子字符串
4. 再就是有一點(diǎn)很重,把被測(cè)試方法寫(xiě)在 expectedEx.expectXxx() 方法后面,不然也不能正確測(cè)試的異常
5. 最后一個(gè)是,只要測(cè)試方法直接拋出被測(cè)試方法的異常即可,并不影響你所關(guān)心的異常
前面說(shuō)到用 try…catch 的辦法也能正確測(cè)試到異常,@Test(expected=…) 或 @Rule 與 try…catch 的方法對(duì)比有什么好處呢,顯然用 JUnit 4 推薦的方法簡(jiǎn)潔明了。再來(lái)看測(cè)試失敗時(shí) JUnit 會(huì)為你提示什么呢?
try…catch 測(cè)試異常失敗時(shí),得到的提示:
無(wú)異常時(shí):
java.lang.AssertionError: No exception thrown. at org.junit.Assert.fail(Assert.java:91) at cc.unmi.PasswordTest.passwordLengthLessThan6LettersThrowsException(PasswordTest.java:20)
異常類型不對(duì)或異常的 message 不對(duì)時(shí):
java.lang.AssertionError: at org.junit.Assert.fail(Assert.java:91) at org.junit.Assert.assertTrue(Assert.java:43) at org.junit.Assert.assertTrue(Assert.java:54) at cc.unmi.PasswordTest.passwordLengthLessThan6LettersThrowsException(PasswordTest.java:22)
上面能提供給我們的定位錯(cuò)誤的幫助不是特別大
再看 @Test(expected=BizException.class) 時(shí)測(cè)試失敗時(shí)的提示:
java.lang.AssertionError: Expected exception: cc.test.BizException at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:32) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
用 @Rules ExpectedException方式來(lái)測(cè)試異常,失敗時(shí)的提示:
java.lang.AssertionError: Expected: (exception with message a string containing “YES. required” and an instance of java.lang.NullPointerException) got: at org.junit.Assert.assertThat(Assert.java:778) at org.junit.Assert.assertThat(Assert.java:736) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:114)
特別是 @Rules ExpectedException 方法時(shí)為何測(cè)試失敗提示的清清楚楚。期望什么異常,異常 message 中含何字符串,實(shí)際上確得到什么類型的異常,異常中 message 是什么。有了這,你一看到就知道怎么去修補(bǔ)你的程序。
相關(guān)文章
Mybatis傳遞多個(gè)參數(shù)的三種實(shí)現(xiàn)方法
這篇文章主要介紹了Mybatis傳遞多個(gè)參數(shù)的三種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Java序列化JSON丟失精度問(wèn)題的解決方法(修復(fù)Long類型太長(zhǎng))
這篇文章主要給大家介紹了關(guān)于Java序列化JSON丟失精度問(wèn)題的解決方法,修復(fù)Long類型太長(zhǎng)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03
解析Java中未被捕獲的異常以及try語(yǔ)句的嵌套使用
這篇文章主要介紹了Java中未被捕獲的異常以及try語(yǔ)句的嵌套使用,是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
淺談idea中導(dǎo)入maven項(xiàng)目的兩種方式
本文主要介紹了淺談idea中導(dǎo)入maven項(xiàng)目的兩種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Java基礎(chǔ)學(xué)習(xí)之ArrayList類概述與常用方法
這篇文章主要為大家簡(jiǎn)單的介紹Java中ArrayList類的概述、常用方法及存儲(chǔ)字符串并遍歷,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-08-08
SpringMVC @RequestBody 為null問(wèn)題的排查及解決
這篇文章主要介紹了SpringMVC @RequestBody 為null問(wèn)題的排查及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法
這篇文章主要介紹了關(guān)于spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12

