Junit 介紹:java
Junit是一套框架(用於JAVA語言),由 Erich Gamma 和 Kent Beck 編寫的一個迴歸測試框架(regression testing framework),即用於白盒測試。數據庫
本文介紹的內容:框架
1 Junit Myeclipse測試類的生成eclipse
2 JUnit 4 經常使用的幾個annotation 介紹與使用 (@Before @After @Test @Ignore @BeforeClass @AfterClass)函數
3 經常使用的斷言介紹oop
4 特殊的處理 (限時測試,異常測試)單元測試
5 參數化配置 (@Parameters)測試
準備測試代碼this
測試的方法(正確、錯誤方法、死循環、拋異常)spa
LogicService
package com.logic; public class LogicService { public int add(int x ,int y){ //加法 return x+y; } public int sub(int x ,int y){ //減法 return x-y; } public int div(int x ,int y){ //除法 return x/y; } public int div2(int x ,int y){ //除法 作了異常判斷 try { int z = x/y; } catch (Exception e) { e.printStackTrace(); } return x/y; } public void loop(int x ,int y){ //死循環 for(;;) x=y; } public void unCompleted(int x ,int y){ //未完成的模塊 //還在開發中 } }
一 Myeclipse測試類的生成
1 對須要測試的類點右鍵 NEW 一個Junit Test Case
2 點擊NEXT
注意 1 選擇NEW Junit 4 test
2 source folder 是默認會填寫上以前右鍵NEW的那個類,若是不是的話,請自行進行修改
3 package 默認會填寫當前的包名 我的建議從新開個測試包-即在包後面加上.test 表示是單元測試用例專用包與源代碼分離
4 name 默認會在以前右鍵NEW的那個類的基礎的後面加上Test 若是不是的話,建議自行進行修改,便於標示
5 初始化的方法,我通常會勾上個setUp,這個請隨意。
3 繼續點擊NEXT
1 這裏能夠選擇須要測試的方法,我通常都是全選的而後在生成的測試類中再作處理
2 點擊finish完成
4 生成的單元測試類
package com.logic.test; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class LogicServiceTest { @Before public void setUp() throws Exception { } @Test public void testAdd() { fail("Not yet implemented"); } @Test public void testSub() { fail("Not yet implemented"); } @Test public void testDiv() { fail("Not yet implemented"); } @Test public void testDiv2() { fail("Not yet implemented"); } @Test public void testLoop() { fail("Not yet implemented"); } @Test public void testUnCompleted() { fail("Not yet implemented"); } }
二 JUnit 4 經常使用的幾個annotation 介紹與使用 (@Before @After @Test @Ignore @BeforeClass @AfterClass)
1 經常使用的annotation介紹
@Before:初始化方法,在任何一個測試執行以前必須執行的代碼;
@After:釋放資源,在任何測試執行以後須要進行的收尾工做。在每一個測試方法執行以後執行一次,該annotation只能修飾public void 方法;
@Test:測試方法,代表這是一個測試方法。在Junit中將會自動被執行。該annotation只你呢個修飾public void 方法。
@Ignore:忽略的測試方法,標註的含義就是「某些方法還沒有完成,暫不參與這次測試」;
@BeforeClass:針對全部測試,只執行一次,且必須爲public static void;通常用於初始化必要的消耗較大的資源,例如數據庫鏈接等
@AfterClass:針對全部測試,將會在全部測試方法執行結束後執行一次,且必須爲public static void;
2 經常使用的annotation測試
修改單元測試類LogicServiceTest
package com.logic.test; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; public class LogicServiceTest { @Before public void setUp() throws Exception { System.out.println("@Before");//測試@Before } @After public void end() throws Exception { System.out.println("@After");//測試@@After } @BeforeClass public static void init() throws Exception { System.out.println("@BeforeClass");//測試@BeforeClass } @AfterClass public static void disstroy() throws Exception { System.out.println("@AfterClass");//測試@AfterClass } @Test public void testAdd() { System.out.println("@Test testAdd");//測試@Test } @Test public void testSub() { System.out.println("@Test testSub");//測試@Test } @Ignore public void testDiv() { System.out.println("@Ignore ");//測試@Ignore } @Ignore public void testDiv2() { System.out.println("@Ignore ");//測試@Ignore } @Ignore public void testLoop() { System.out.println("@Ignore ");//測試@Ignore } public void testUnCompleted() { System.out.println("@Ignore ");//測試未標註 } }
執行結果
執行結果分析
1 @BeforeClass和@AfterClass只執行一次,在全部方法開始前/後
2 @Before和@After在每一個@Test標註的方法先後各執行一次
3 @Test 標註的方法都會執行一次(表示要測試的方法)
4 @Ignore方法不會被執行,沒有annotation的方法也不會被執行
5 總結 @BeforeClass –> (@Before –> @Test –> @After) –> @AfterClass
理解了以上註解後就能夠嘗試着在平常的項目中使用Junit進行單元測試了。
3 經常使用的斷言介紹
assertEquals(String msg, Object expectRes, Object Res) -------- 用於值判斷
判斷expectRes.equals(Res) ,表示值等於的判斷,失敗則拋MSG
assertSame(String msg, Object expectRes, Object Res) -------- 用於地址判斷
判斷expectRes==Res,表示地址等於的判斷,失敗則拋MSG
assertTrue(String msg,Boolean result) ----------------------------用於Boolean判斷
判斷result是true仍是false,失敗則拋MSG
assertNull(String msg,Object result)-------------------------------用於NULL判斷
判斷result是否爲NULL,失敗則拋MSG
fail(String msg);---------------------------------------------------直接停止方法運行
直接停止方法運行,拋出MSG
測試代碼
package com.logic.test; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import com.logic.LogicService; public class LogicServiceTest { LogicService logserv ; @Before public void setUp() throws Exception { logserv = new LogicService(); } @Test public void testAdd() { String a = "aa"; String t = "a"; String b = "a"+t; assertEquals("assertEquals", a, b) ; //A與B的關係是值相等,地址不相等,這個用例會成功 } @Test public void testSub() { String a = "aa"; String t = "a"; String b = "a"+t; assertSame("assertSame", a, b) ; //A與B的關係是值相等,地址不相等,這個用例會失敗 } @Test public void testDiv() { assertTrue("assertTrue",true);//用例成功 assertTrue("第二個爲false失敗",false);//用例失敗 } @Test public void testDiv2() { assertNull("assertNull",null);//用例成功 assertNull("第二個爲notNull失敗","a");//用例失敗 } @Ignore public void testLoop() { } @Ignore public void testUnCompleted() { } }
執行結果分析
這裏我再也不截圖了
1 成功
2 失敗,返回MSG爲assertSame
3 第一個成功,第二個失敗,返回MSG爲第二個爲false失敗
4 第一個成功,第二個失敗,返回MSG爲第二個爲notNull失敗
斷言是用來判斷被測方法執行的結果與預期結果是否匹配
4 特殊的處理 (限時測試,異常測試)
1 Junit提供限時處理的機制。
@Test(timeout=1000) 單位毫秒
當方法用時超過1000毫秒時,此方法會自動停止並執行失敗
package com.logic.test; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import com.logic.LogicService; public class LogicServiceTest { LogicService logserv ; @Before public void setUp() throws Exception { logserv = new LogicService(); } @Ignore public void testAdd() { } @Ignore public void testSub() { } @Ignore public void testDiv() { } @Test(timeout=1000) public void testDiv2() { System.out.print("我不會超過1000毫秒的"); } @Test(timeout=1000) public void testLoop() { logserv.loop(1, 1);//此方法使用的是死循環實現,因此必定會超過限時,超過限時後此方法會自動停止 } @Ignore public void testUnCompleted() { } }
執行結果
loop方法超時報錯,div2方法不超時成功
2 Junit提供異常處理的機制。
@Test(expected=Exception.class) 其中Exception.class能夠寫的更加具體
測試
@Test(expected=Exception.class) public void testDiv() { System.out.print(logserv.div(3, 0)); } @Test(expected=Exception.class) public void testDiv2() { System.out.print(logserv.div(3, 0)); }
執行結果
兩個都經過
測試
@Test(expected=Exception.class) public void testDiv() { System.out.print(logserv.div(3, 0)); } @Test public void testDiv2() { System.out.print(logserv.div(3, 0)); }
執行結果
第一個經過 第二個不經過 異常爲除數不能爲zero
5 參數化配置 (@Parameters) 重要
進行單元測試的時候,一般一個方法須要好幾個case進行測試,Junit提供參數化便於咱們對方法進行多種參數的組合測試
若是不使用參數化進行測試的話,那麼咱們的測試類會作的很臃腫
例如
@Test public void testAdd() { assertEquals("1+1 失敗",2,logserv.add(1, 1) ); } @Test public void testAdd1() { assertEquals("1+2 失敗",3,logserv.add(1, 2) ); } @Test public void testAdd2() { assertEquals("1+3 失敗",3,logserv.add(1, 3) ); } @Test public void testAdd3() { assertEquals("1+4 失敗",3,logserv.add(1, 4) ); }
這樣的測試類顯然看起來不是很理想,代碼過於重複
參數化的實現過程(重要)
1 在測試類上增長
@RunWith(Parameterized.class)並引入
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
2 寫上構造類的函數及定義入參
例如
@RunWith(Parameterized.class) public class LogicServiceTest { LogicService logserv ; int parm1 ;//定義入參 int parm2 ;//定義入參 int res;//定義入參 public LogicServiceTest(int parm1,int parm2,int res){//定義構造函數 this.parm1=parm1; this.parm2=parm2; this.res=res; }
3 定義一個返回結果爲collection類型的方法並寫上@Parameters
注意 Arrays.asList()裏面NEW的Object的要與定義的參數一一對應
例如
public class LogicServiceTest { LogicService logserv ; int parm1 ;//定義入參 int parm2 ;//定義入參 int res;//定義入參 public LogicServiceTest(int parm1,int parm2,int res){//定義構造函數 this.parm1=parm1; this.parm2=parm2; this.res=res; } @Parameters public static Collection<Object[]> initParm(){ return Arrays.asList(new Object[][]{ {1,1,2},{1,2,3},{1,3,4},{1,3,5}//{}裏的參數必定要和構造函數一一對應 }); }
4 編寫測試方法,調用參數
@Test public void testAdd() { assertEquals(res,logserv.add(parm1, parm2)); }
5 測試類代碼全景(準備執行)
package com.logic.test; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import com.logic.LogicService; @RunWith(Parameterized.class) public class LogicServiceTest { LogicService logserv; int parm1;// 定義入參 int parm2;// 定義入參 int res;// 定義入參 public LogicServiceTest(int parm1, int parm2, int res) {// 定義構造函數 this.parm1 = parm1; this.parm2 = parm2; this.res = res; } @Parameters public static Collection<Object[]> initParm() { return Arrays.asList(new Object[][] { { 1, 1, 2 }, { 1, 2, 3 }, { 1, 3, 4 }, { 1, 3, 5 } // {}裏的參數必定要和構造函數一一對應 }); } @Before public void setUp() throws Exception { logserv = new LogicService(); } @Test public void testAdd() { assertEquals(res, logserv.add(parm1, parm2)); } @Ignore public void testSub() { } }
6 執行結果
總結:使用了參數化後測試類的代碼簡化了很多,並且執行起來效果很不錯
收尾
經過本文能夠了解到:
1 Junit Myeclipse測試類的生成
2 JUnit 4 經常使用的幾個annotation 介紹與使用 (@Before @After @Test @Ignore @BeforeClass @AfterClass)
3 經常使用的斷言介紹
4 特殊的處理 (限時測試,異常測試)
5 參數化配置 (@Parameters)