Java—JUnit測試

使用JUnit做測試目的是儘量早的發現程序的bug,一個bug隱藏的時間越久,修復他的代價就越大。
1、JUnit簡介:
    JUnit最初是由Erich Gamma 和 Kent Beck 編寫的一個迴歸測試框架(regression testing framework),爲單元測試(Unit Test)的支持框架。用來編寫和執行重覆性的測試。即所謂白盒測試。
它包括了以下的特性:
  1 對預期結果作斷言
  2 提供測試裝備的生成與銷燬
  3 易於組織執行測試
  4 圖形與文字界面的測試器

2、JUnit的環境配置
環境:Eclipse 中配置JUnit,選擇項目JUnit4(在Package Explorer中) -> 右擊鼠標 -> 選擇Properties -> 選擇Java Build Path (在左邊的菜單中) -> 在右邊選擇標籤 Libraries  -> 單擊按鈕“Add Library”  -> 選擇JUnit , 單擊按鈕 “Next>”  -> 選擇JUnit library version 爲: JUnit4 -> 單擊按鈕“Finish” –> 單擊按鈕 “OK”
 JUnit4是JUnit框架有史以來的最大改進,其主要目標是利用java5的Annotation特性來簡化測試用例的編寫。JUnit4的官方網址是http://www.junit.org/。
3、總結一下3-4的不同,及4的改進
下面我們以一個簡單的例子來介紹如何使用 JUnit4同JUnit3編寫測試用例:
public Class XXXX{
     public String hello(){
     return “hello”;
      }
}
對於這個類的用JUnit3編寫測試用例:
import junit.framework.TestCase;
   public Class XXXXTest extends TestCase{
   public void testHello(){
   asssertEqual(new XXXX().Hello(),”hello”);
  }
}
用JUnit4編寫測試用例:
import static org.junit.framework.assertEqual;
import org.junit.Test;
//這兩個是junit4中必須導入的s
public Class XXXXTest{
@Test
public void helloTest(){
    asssertEqual(new XXXX().Hello(),”hello”);
}
}
從上面例子我們對JUnit3和JUnit4有了一個初步的印象,下面我們重點介紹JUnit4與JUnit3的主要區別。
JUnit3  JUnit4
必須引入類TestCase
import junit.framework.TestCase; 必須引入
import org.junit.Test;
import static org.junit.Assert.*;
必須繼承類TestCase
class BaseClassTest extends TestCase 不需要
測試方法必須以test開頭
public void testMethod () 不需要,
但是類開始的時候要標記 @Test
通過assert*方法來判斷結果
assertTrue(baseClass.method ().equals(“test.junit.BaseClass”));
3.1 JUnit4引入了java 5.0的註釋技術:
    這兩個版本最大的區別在JUnit3.x中測試必須繼承 TestCase,並且每個方法名必須以test開頭。比如:testMethod1()而在JUnit4.x中不必繼承TestCase,採用了註解的方式。只要在測試的方法上加上註解@Test即可,從而不必再遵循以前的一些顯式約定和反射定位測試;在JUnit4.x中如果繼承了TestCase,註解就不起作用了。並且有很重要的一點就是在JUnit4.x中繼承了TestCase後,在OutLine視圖中測試單個方法時,結果整個類都run 了。還有一點就是,在3.x中需要實現setUp和tearDown方法,而在4.x中無需這樣,可以自定義需要在測試前和測試後的方法,在方法前加上 @before,@after就可以了。所以在JUnit4.x不必繼承TestCase用註解即可對單個方法進行測試。
3.2 JUnit4引入了一個JUnit3中沒有的新特性——類範圍的 setUp() 和tearDown() 方法。任何用 @BeforeClass 註釋的方法都將在該類中的測試方法運行之前剛好運行一次,而任何用 @AfterClass 註釋的方法都將在該類中的所有測試都運行之後剛好運行一次。
3.3 異常測試:
    異常測試是JUnit4中的最大改進。JUnit3的異常測試是在拋出異常的代碼中放入try塊,然後在try塊的末尾加入一個fail()語句。
    例如該方法測試一個被零除拋出一個ArithmeticException:
    該方法不僅難看,而且試圖挑戰代碼覆蓋工具,因爲不管測試是否通過還是失敗,總有一些代碼不被執行。
在JUni4中,可以編寫拋出異常的代碼,並使用註釋來聲明該異常是預期的:如果沒有異常拋出或者拋出一個不同的異常,那麼測試就將失敗。
3.4 JUnit4添加了兩個比較數組的assert() 方法:
    public static void assertEquals(Object[] expected, Object[] actual)
public static void assertEquals(String message, Object[] expected, Object[] actual)
這兩個方法以最直接的方式比較數組:如果數組長度相同,且每個對應的元素相同,則兩個數組相等,否則不相等。數組爲空的情況也作了考慮。
 
    assertEquals()方法用來斷定您希望的預期結果與單元方法實際的傳回結果是否相同,如果不同則發出斷言
JUnit4 常用的幾個annotation 介紹
★ @Before:初始化方法,在任何一個測試執行之前必須執行的代碼;
★ @After:釋放資源,在任何測試執行之後需要進行的收尾工作。在每個測試方法執行之後執行一次,該annotation只能修飾public void 方法;
★ @Test:測試方法,表明這是一個測試方法。在JUnit中將會自動被執行。該annotation只你呢個修飾public void 方法。對於方法的聲明也有如下要求:名字可以隨便取,沒有任何限制,但是返回值必須爲void,而且不能有任何參數。如果違反這些規定,會在運行時拋出一個異常。至於方法內該寫些什麼,那就要看你需要測試些什麼了;在這裏可以測試期望異常和超時時間,如 @Test(timeout = 100):我們給測試函數設定一個執行時間,超過了這個時間(100毫秒),它們就會被系統強行終止,並且系統還會向你彙報該函數結束的原因是因爲超時,這樣你就可以發現這些Bug了。
★ @Ignore:忽略的測試方法,標註的含義就是“某些方法尚未完成,暫不參與此次測試”;這樣的話測試結果就會提示你有幾個測試被忽略,而不是失敗。一旦你完成了相應函數,只需要把@Ignore標註刪去,就可以進行正常的測試。
★ @BeforeClass:針對所有測試,只執行一次,且必須爲public static void;
★ @AfterClass:針對所有測試,將會在所有測試方法執行結束後執行一次,且必須爲public static void;
所以一個JUnit4 的單元測試用例執行順序爲:@BeforeClass –> @Before –> @Test –> @After –> @AfterClass;每一個測試方法的調用順序爲:@Before –> @Test –> @After。
如下面例子:
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 JUnit4Test {
@Before
public void before() {
System.out.println(“@Before”);
}
@Test
public void test() {
System.out.println(“@Test”);
assertEquals(5 + 5, 10);
}
@Ignore
@Test
public void testIgnore() {
System.out.println(“@Ignore”);
}
@Test(timeout = 50)
public void testTimeout() {
System.out.println(“@Test(timeout = 50)”);
assertEquals(5 + 5, 10);
}
@Test(expected = ArithmeticException.class)
public void testExpected() {
System.out.println(“@Test(expected = Exception.class)”);
throw new ArithmeticException();
}
@After
public void after() {
System.out.println(“@After”);
}
@BeforeClass
public static void beforeClass() {
System.out.println(“@BeforeClass”);
};
@AfterClass
public static void afterClass() {
System.out.println(“@AfterClass”);
};
};
右擊測試類,選擇JUnit運行……
輸出結果如下:
@BeforeClass
@Before
@Test(timeout = 50)
@After
@Before
@Test(expected = Exception.class)
@After
@Before
@Test
@After
@AfterClass
在eclipse中JUnit運行結果視圖中可以看到testIgnore是被忽略的,沒有執行;還有其中有一個方法運行報錯。
4、常用的斷言介紹
 4.1 、assertEquals([String message],Object target,Object result)
target與result不相等,中斷測試方法,輸出message
assertNull   斷言對象爲null,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
assertEquals(a, b) 測試a是否等於b(a和b是原始類型數值(primitive value)或者必須爲實現比較而具有equal方法)
assertEquals
斷言兩個對象相等,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
例如計算器加法功能的測試可以使用一下驗證:
Assert.assertEquals(0,result);
4.2  assertTrue/False([String message],Boolean result)
Result爲 false/true,中斷測試方法,輸出message
assertTrue
斷言條件爲真,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
assertFalse(a) 測試a是否爲false(假),a是一個Boolean數值。
assertFalse
斷言條件爲假,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
4.3  assertNotNull/Null([String message],Obejct result
Retult= = null/result!=null,中斷測試方法,輸出message
assertNotNull(a) 測試a是否非空,a是一個對象或者null。
assertNotNull 斷言對象不爲null,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
4.4  assertSame/NotSame(Object target,Object result)
Traget與result 不指向/指向 同一內存地址(實例),中斷測試方法,輸出message
assertNotSame(a, b) 測試a和b是否沒有都引用同一個對象。
assertNotSame
斷言兩個引用指向不同對象,若不滿足,方法拋出帶有相應信息的AssertionFailedError異常。
assertSame 斷言兩個引用指向同一個對象,若不滿足,方法拋出帶有相應信息AssertionFailedError異常。
4.5  fail([String message])
中斷測試方法,輸出message
Fail  讓測試失敗,並給出指定信息。
 
Java代碼
@Test 
    public void add(){  
        assertEquals("不相等","1","1");  
          
    } 
@Test
     public void add(){
 assertEquals("不相等","1","1");
      }
 JUnit4中測試類不需要繼承自TestCase。不繼承TestCase就無法調用assertXXX方法了,正因爲如此,所有的assertXXX方法全部以靜態方法被放入了Assert類,使用Assert.assertXXX()調用。使用方法是
 
Java代碼
import static org.junit.Assert.*; 
import static org.junit.Assert.*;
 
 setUp()和tearDown()方法也依賴@Before和@After標記,這樣做的最大的好處是在繼承體系內不必擔心忘記了在setUp()方法中調用父類的super.setUp()方法,JUnit框架會自動處理父類的@Before和@After標記的方法。
並且,JUnit框架對@Before和@After的調用順序類似於類的構造方法和析構方法,即@Before按照父類到子類的順序調用,@After則相反,這樣保證了資源的正確獲取和釋放。
當然,不再強迫必須使用setUp和tearDown作爲方法名,可以使用更有意義的方法名,例如:initDatabase()和closeDatabase(),只要它們被標註了@Before和@After即可。
Java代碼
@Before
public void test1(){
 System.out.println("開始初始化----");
}
@After
 public void test2(){
  System.out.println("銷燬資源----");
 }
 
JUnit4另一個較大的變化是引入了@BeforeClass和@AfterClass,它們在一個Test類的所有測試方法執行前後各執行一次。這是爲了能在@BeforeClass中初始化一些昂貴的資源,例如數據庫連接,然後執行所有的測試方法,最後在@AfterClass中釋放資源。
正如你能想到的,由於@BeforeClass和@AfterClass僅執行一次,因此它們只能標記靜態方法,在所有測試方法中 共享的資源也必須是靜態引用:
     
Java代碼
 @BeforeClass
 public static void  test11(){
  System.out.println("所有方法調用前要做的事情");
 }
@AfterClass
 public static  void test22(){
  System.out.println("所有方法測試完後要調用的");
 }
 
JUnit4可以使用expected=Exception.class來期待一個預期的異常,而不必編寫
try{
    fail("No exception")
}catch(Exception e){
   //Ok
}
例如:測試數組長度越界的異常。
Java代碼
@Test(expected= IndexOutOfBoundsException.class)   
    public void empty() {  
        System.out.println("IndexOutOfBoundsException");  
        new ArrayList().get(0);   
    } 
@Test(expected= IndexOutOfBoundsException.class)
 public void empty() {
  System.out.println("IndexOutOfBoundsException");
     new ArrayList().get(0);
 }
 
對於非常耗時的測試,@Test還有一個timeout來標識該方法最長執行時間,超過此時間即表示該測試方法失敗:
Java代碼
@Test(timeout=1)   
 public void infinity() {  
       while(true);  
  } 
 @Test(timeout=1)
  public void infinity() {
        while(true);
   }
 
以上方法若執行時間超過1ms則測試失敗,由於依賴CPU的執行速度,在不同的機器上測試結果也不同。
 
運行多個測試用例:
Java代碼
JUnitCore.runClasses(MyTest.class);
 
runClasses方法的參數可以寫多個測試類的class
  
 下面是一個簡單的測試用例。
Java代碼
import static org.junit.Assert.*;  
 
import java.util.ArrayList;  
 
import org.junit.After;  
import org.junit.AfterClass;  
import org.junit.Before;  
import org.junit.BeforeClass;  
import org.junit.Test;  
 
public class MyTest {  
    @Before 
    public void test1(){  
        System.out.println("開始初始化----");  
    }  
    @BeforeClass 
    public static void  test11(){  
        System.out.println("所有方法調用前要做的事情");  
    }  
      
    @Test 
    public void add(){  
        assertEquals("不相等","1","1");  
          
    }  
    @Test 
    public void add2(){  
        System.out.println("測試用例2");  
        assertEquals("不相等","1","1");  
          
    }  
    @Test(expected= IndexOutOfBoundsException.class)   
    public void empty() {  
        System.out.println("IndexOutOfBoundsException");  
        new ArrayList().get(0);   
    }  
     @Test(timeout=1)   
     public void infinity() {  
           while(true);  
      }  
 
    @After 
    public void test2(){  
        System.out.println("銷燬資源----");  
    }  
      
    @AfterClass 
    public static  void test22(){  
        System.out.println("所有方法測試完後要調用的");  
    }  
 

import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class MyTest {
 @Before
 public void test1(){
  System.out.println("開始初始化----");
 }
 @BeforeClass
 public static void  test11(){
  System.out.println("所有方法調用前要做的事情");
 }
 
 @Test
 public void add(){
  assertEquals("不相等","1","1");
  
 }
 @Test
 public void add2(){
  System.out.println("測試用例2");
  assertEquals("不相等","1","1");
  
 }
 @Test(expected= IndexOutOfBoundsException.class)
 public void empty() {
  System.out.println("IndexOutOfBoundsException");
     new ArrayList().get(0);
 }
  @Test(timeout=1)
  public void infinity() {
        while(true);
   }

 @After
 public void test2(){
  System.out.println("銷燬資源----");
 }
 
 @AfterClass
 public static  void test22(){
  System.out.println("所有方法測試完後要調用的");
 }
}
 
運行測試用例:
 
Java代碼
import junit.framework.JUnit4TestAdapter;  
 
import org.junit.runner.JUnitCore;  
 
public class MyTest3 {  
    public static void main(String[] args) {  
        JUnitCore.runClasses(MyTest.class);  
        System.out.println();  
        //MyTest3.suite();  
    }  
 
    public static junit.framework.Test suite() {   
        return new JUnit4TestAdapter(MyTest.class);   
    }  
 
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章