JUnit測試框架使用介紹

JUnit 是由 Erich Gamma Kent Beck 編寫的一個迴歸測試框架( regression testing framework )。 Junit 測試是程序員測試,即白盒測試。該項目主頁 :[url]http://www.junit.org/[/url]
 
JUnit 測試骨架
使用 JUnit 時,主要都是經過繼承 TestCase 類別來撰寫測試用例,使用 testXXX() 名稱來撰寫單元測試。
JUnit 寫測試真正所須要的就三件事:
1   一個 import 語句引入全部 junit.framework.* 下的類。
2   一個 extends 語句讓你的類從 TestCase 繼承。
3   一個調用 super(string) 的構造函數。
功能類 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;
    }
}
測試類 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));
    }
}
使用 Eclipse-Run As JUnit Test
在運行 TestRunner 執行測試時,你會發現到有 Failure Error 兩種測試還沒有經過的信息。
Failure 指的是預期的結果與實際運行單元的結果不一樣所致使,例如當使用 assertEquals() 或其它 assertXXX() 方法斷言失敗時,就會回報 Failure ,這時候要檢查你的單元方法中的邏輯設計是否有誤。
Error 指的是你的程序沒有考慮到的狀況,在斷言以前程序就由於某種錯誤引起例外而終止,例如在單元中存取某個數組,由於存取超出索引而引起 ArrayIndexOutOfBoundsException ,這會使得單元方法沒法正確完成,在測試運行到 asertXXXX() 前就提早結束,這時候要檢查你的單元方法中是否有未考慮到的狀況而引起流程忽然中斷。
 
JUnit 的各類斷言
JUnit 提供了一些輔助函數,用於幫助你肯定某個被測試函數是否工做正常。一般而言,咱們把全部這些函數統稱爲斷言。斷言是單元測試最基本的組成部分。
1. assertEquals([String message], expected,actual)
比較兩個基本類型或對象是否相等( expected actual 是原始類型數值 (primitive value) 或者必須爲實現比較而具備 equal 方法);
2.assertFalse([String message],boolean condition)
對布爾值求值,看它是否爲
3.assertTrue([String message],boolean condition)
對布爾值求值,看它是否爲
4.assertNull([String message],java.lang.Object object)
檢查對象是否爲
5.assertNotNull([String message],java.lang.Object object)
檢查對象是否不爲
6.assertSame([String message],expected,actual)
檢查兩個對象是否爲同一實例;
7.assertNotSame([String message],expected,actual)
檢查兩個對象是否不爲同一實例;
8. fail( String message )
使測試當即失敗,其中 message 參數使可選的。這種斷言一般被用於標記某個不該該到達的分支(例如,在一個預期發生的異常以後)
 
一個 TestCase 測試實例
下面是一個數字功能類,它提供了求最大值函數和求最小值函數:
package com.zj.c01;
 
public class NumberTool {
    public static int getMax( int [] arr) {
       int max = Integer. MIN_VALUE ;
        if (arr. length == 0)
           throw new RuntimeException( "Empty list" );
       for ( int index = 0; index < arr. length ; index++) {
           if (arr[index] > max)
              max = arr[index];
       }
       return max;
    }
 
    public static int getMin( int [] arr) {
       int min = Integer. MAX_VALUE ;
       if (arr. length == 0)
           throw new RuntimeException( "Empty list" );
       for ( int i = 0; i < arr. length ; i++) {
           if (arr[i] < min)
              min = arr[i];
       }
       return min;
    }
}
下面針對求最大值函數編寫測試用例:
1. 簡單測試: [7,8,9]->9
2. 位序測試: [9,8,7] ->9 [7,9,8] ->9 [8,7,9] ->9
3. 重複值測試: [9,7,9,8] ->9
4. 單值測試: [1]->1
5. 負值測試: [-7,-8,-9]->-7
6. 空值測試: []-> 拋出異常;
測試類 NumberToolTest
package com.zj.c01;
import junit.framework.TestCase;
 
public class NumberToolTest extends TestCase {
    public NumberToolTest(String name) {
       super (name);
    }
 
    public void testSimple() {
       assertEquals(9, NumberTool.getMax( new int [] { 7, 8, 9 }));
    }
 
    public void testOrder() {
       assertEquals(9, NumberTool.getMax( new int [] { 9, 8, 7 }));
       assertEquals(9, NumberTool.getMax( new int [] { 7, 9, 8 }));
       assertEquals(9, NumberTool.getMax( new int [] { 8, 7, 9 }));
    }
 
    public void testDups() {
       assertEquals(9, NumberTool.getMax( new int [] { 9, 7, 9, 8 }));
    }
 
    public void testOne() {
       assertEquals(1, NumberTool.getMax( new int [] { 1 }));
    }
 
    public void testNegitave() {
       assertEquals(-7, NumberTool.getMax( new int [] { -7, -8, -9 }));
    }
 
    public void testEmpty() {
       try {
           NumberTool.getMax( new int [] {});
           fail( "Should have thrown an exception" );
       } catch (RuntimeException e) {
           assertTrue( true );
       }
    }
}
使用 Eclipse-Run As JUnit Test
 
JUnit 和異常
對於測試而言,下面兩種異常是咱們可能會感興趣的:
1   從測試代碼拋出的可預測異常。
2   因爲某個模塊(或代碼)發生嚴重錯誤,而拋出的不可預測異常。
任何對 assertTrue(true) 的使用都應該被翻譯爲「我預期控制流程會達到這個地方」。一般而言,對於方法中每一個被指望的異常,你都應該寫一個專門的測試來確認該方法在應該拋出異常的時候確實會拋出異常。如上例中 testEmpty() 測試方法的設計。
對於處於出乎意料的異常,你最好簡單的改變你的測試方法的聲明讓它能拋出可能的異常。 JUnit 框架能夠捕獲任何異常,而且把它報告爲一個錯誤,這些都不須要你的參與。
 
Per-method SetupTear-down
對於重複出如今各個單元測試中的運行環境,能夠集中加以管理,能夠在繼承TestCase以後,從新定義setUp()tearDown()方法,將數個單元測試所須要的運行環境在setUp()中建立,並在tearDown()中銷燬。
JUnit TestCase 基類提供兩個方法供你改寫,分別用於環境的創建和清理:
protected void setup();
protected void teardown();
 
測試類 MathToolTest2
package com.zj.c01;
import junit.framework.TestCase;
 
public class NumberToolTest2 extends TestCase {
    private int [] arr ;
 
    public NumberToolTest2(String name) {
       super (name);
    }
 
    protected void setUp() throws Exception {
       super .setUp();
       arr = new int [] { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 };
    }
 
    protected void tearDown() throws Exception {
       super .tearDown();
       arr = null ;
    }
 
    public void testMax() {
       assertEquals(5, NumberTool.getMax( arr ));
    }
 
    public void testMin() {
       assertEquals(-5, NumberTool.getMin( arr ));
    }
}
 
TestSuite
每個定義好的TestCase,都使用TestRunner來運行測試,事實上TestRunner並不直接運行TestCase上的單元方法,而是經過TestSuite TestSuite能夠將數個TestCase組合在一塊兒。
在上面的例子中,並無看到任何的TestSuite,這是由於TestRunnerrun()方法中會創建TestSuite
static public void run(Class testClass) {
    run( new TestSuite(testClass));
}
在這個TestSuite的建構式中,會使用反射自動找出testXXX()方法,並加入待執行的測試方法, TestRunnerrun()方法中會去執行TestSuite上的run()方法,而後TestSuite會將之委託給TestCase上的 run()方法,而該run()方法中執行每個testXXX()方法。
若是你只想執行某TestCase中的部分測試函數,則可本身構建TestSuite,下面的代碼針對NumberToolTest中的兩個測試函數testSimple()testNegitave()進行測試。
package com.zj.c02;
import com.zj.c01.NumberToolTest;
import junit.framework.Test;
import junit.framework.TestSuite;
 
public class PartTest {
    public static Test suite() {
       TestSuite suite = new TestSuite();
       suite.addTest( new NumberToolTest( "testSimple" ));
       suite.addTest( new NumberToolTest( "testNegitave" ));
       return suite;
    }
}
使用 Eclipse-Run As JUnit Test
你也能夠組合多個testCase,下面的代碼將MathToolTestNumberToolTest集中到一個TestSuite中:
package com.zj.c02;
import com.zj.c01.MathToolTest;
import com.zj.c01.NumberToolTest;
import junit.framework.Test;
import junit.framework.TestSuite;
 
public class CompositeTest {
    public static Test suite() {
       TestSuite suite = new TestSuite( "Running all tests." );
       suite.addTestSuite(MathToolTest. class );
       suite.addTestSuite(NumberToolTest. class );
       return suite;
    }
}
使用 Eclipse-Run As JUnit Test
 
Per-suite Setup Tear-down
通常而言,你只須針對每一個方法設置運行環境;可是在某些狀況下,你須爲整個test suite設置一些環境,以及在test suite中的全部方法都執行完成後作一些清理工做。要達到這種效果,你須要per-suite setupper-suite teardown
Per-suite setup要複雜一些。你須要提供所需測試的一個suite(不管經過什麼樣的方式)而且把它包裝進一個TestSetup對象。注意你能夠在同一個類中同時使用per-sutieper-testsetup()teardown
package com.zj.c02;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;
import com.zj.c01.MathToolTest;
import com.zj.c01.NumberToolTest;
 
public class WrapperCompositeTest {
    public static Test suite() {
       TestSuite suite = new TestSuite( "Running all tests with env." );
       suite.addTestSuite(MathToolTest. class );
       suite.addTestSuite(NumberToolTest. class );
       TestSetup wrapper = new TestSetup(suite) {
           protected void setUp() {
              doSetUp();
           }
 
           protected void tearDown() {
              doTearDown();
           }
       };
       return wrapper;
    }
 
    public static void doSetUp() {
       // initialization codes
    }
 
    public static void doTearDown() {
       // release codes
    }
}
 
參考資料
[1] 單元測試之道 Java —— 使用 Junit, 電子工業出版社
相關文章
相關標籤/搜索