JUnit學習筆記(一)

前言

在慕課網上聽了一位老師的JUnit的基礎講解,感覺對於新人來說還是很友好,故總結下來做此筆記

什麼是單元測試

你的程序主要是由一個個的 Class 組成的,一個類或一個對象當然也是一個單元,而比類更小的單元是類的方法(函式)。如果你的類中的基本單元——如某些方法不能正常工作,在某些輸入條件下會得出錯誤的執行結果,那麼如何保證你的類/對象乃至整個應用軟件或系統作爲一個整體能正常工作呢?所以,簡單說,單元測試(優先)的目的就是首先保證一個系統的基本組成單元、模塊(如對象以及對象中的方法)能正常工作。

爲什麼要進行單元測試

看上去像是增加了代碼量,畢竟光是業務代碼就已經花了我們大部分時間精力,但是實際上卻是減少了我們之後可能對代碼修改的機率,儘可能的實現我們一次性編寫就能成功的這個夢想。

工具

本次筆記採用JUnit4來進行測試。JUnit4比起JUnit3而言使用起來更加容易方便,而且目前爲止要比JUnit5穩定,網上的參考文檔也更多。編譯器採用的eclipse。

什麼是JUnit

基於測試驅動開發的測試框架,是xUnit系列的一個子系列。說簡單點就是一個用於java測試的工具箱,裏面有很多方法和規範可以供我們直接使用。

官網

官網地址
這裏寫圖片描述

  • 第1條是關於如何在項目中配置JUnit,包括具體的jar包,在maven中的配置之類的,但由於本次實驗所使用的編譯器是Eclipse, Eclipse很好的集成了JUnit框架,所以我們也就不用再單獨下載。
  • 第2條是提供一套樣例,方便初學者依葫蘆畫瓢。
  • 第3條是下載的JUnit4的版本。
  • 第4條JUnit的java API文檔。裏面詳細講述了各種方法。
  • 第5條列舉了jUnit使用的語法規範
  • 第6條是指第三方擴展。

基本使用步驟

創建被測試類

  1. 在eclipse裏新建一個工程,取名JUnitDemo,並新建一個名叫Number的類,包名寫上my.demo。這裏寫圖片描述
  2. 給這個Number類裏寫上一些測試用方法,爲了方便我們寫加減乘除即可。
public class Number {

    public int add(int a, int b) {
        return a+b;
    }

    public int subtraction(int a ,int b) {
        return a-b;
    }

    public int division(int a,int b) {
        return a/b;
    }

    public int multiplication(int a,int b) {
        return a*b;
    }
}
  1. 先將jUnit所需的jar包引入項目。右鍵項目->Build Path->Add Libraries。這裏寫圖片描述
    之後會彈出一個框,選擇其中的JUnit
    這裏寫圖片描述
    然後選擇JUnit4,最後Finish即可。
  2. 創建測試類。爲了方便我們以後對測試類進行管理,建議在在和src平級的地方新建一個文件夾叫做“test”,並在裏面創建測試代碼,test文件裏的目錄結構和src的建議保持一致。這裏寫圖片描述
    右鍵被測試類->new->Other這裏寫圖片描述
    之後在文本框中輸入junit,然後選中JUnit Test Case
    這裏寫圖片描述
    彈出一個創建框,點擊browse按鈕選擇路徑爲test包後,點擊next
    這裏寫圖片描述
    隨後勾選該類,選擇所有方法
    這裏寫圖片描述
    測試類就創建完成了
    這裏寫圖片描述

斷言

JUnit測試中使用“斷言”來進行測試。斷言是編寫測試用例的核心實現方式,即對比期望值和測試的結果是否相同,以此來判斷測試是否通過。斷言的核心方法有以下幾種

方法名 作用
assertArrayEquals(expecteds, actuals) 查看兩個數組是否相等
assertEquals(expected, actual) 查看兩個對象是否相等。類似於字符串比較使用的equals()方法
assertNotEquals(first, second) 查看兩個對象是否不相等
assertNull(object) 查看對象是否爲空。
assertNotNull(object) 查看對象是否不爲空。
assertSame(expected, actual) 查看兩個對象的引用是否相等。類似於使用“==”比較兩個對象
assertNotSame(unexpected, actual) 查看運行結果是否爲true。
assertFalse(condition) 查看運行結果是否爲false。
assertThat(actual, matcher) 查看實際值是否滿足指定的條件
fail() 讓測試失敗

註解

註解與註釋不同,註釋是由“//”等開頭,而註解是“@”開頭。兩者的區別是註解不會對程序本身有任何影響,其作用僅僅是方便我們更好的理解代碼。而註解是對程序本身又影響的,它相當於是一個可執行的代碼。
JUnit常用註解及其作用有:

註解名 作用
@Before 初始化方法
@After 釋放資源
@Test 測試方法,在這裏可以測試期望異常和超時時間
@Ignore 忽略的測試方法
@BeforeClass 針對所有測試,只執行一次,且必須爲static void
@AfterClass 針對所有測試,只執行一次,且必須爲static void
@RunWith 指定測試類使用某個運行器
@Parameters 指定測試類的測試數據集合
@Rule 允許靈活添加或重新定義測試類中的每個測試方法的行爲
@FixMethodOrder 指定測試方法的執行順序

測試代碼的編寫

初級使用我們採用assertEquals(excepted, actual)來進行舉例。

public class NumberTest {

    @Test
    public void testAdd() {
        assertEquals(5, new Number().add(2, 3));    //判斷2+3是不是等於5
    }

    @Test
    public void testSubtraction() {
        assertEquals(4, new Number().subtraction(8, 4));    //判斷8-4是不是等於4
    }

    @Test
    public void testDivision() {
        assertEquals(2, new Number().division(10, 5));  //判斷10/5是不是等於2
    }

    @Test
    public void testMultiplication() {
        assertEquals(12, new Number().multiplication(3, 4));    //判斷3*4是不是等於12
    }

}

如果我們想要測試單獨的某個方法,需要右鍵該方法->Run as->JUnit Test,
如果是想要測試一個類中的全部方法,則右鍵類名->Run as ->JUnit Test這裏寫圖片描述
之後會出現一個測試窗體,如果全部是綠條,則表明所測試的對象是無誤的。測試成功。
這裏寫圖片描述

錯誤案例

當綠條變成紅色的時候,代表測試對象有誤,其中包括兩種錯誤,一個是Failure,另一個是Error。Failure的出現代表程序運行的實際值和預期值不符,而Error的出現代表代碼本身有誤或者有隱藏的bug。
這裏我們編寫了兩個錯誤代碼,一個是測試2+3等不等於4,另一個是測試6/0等不等於3。右邊的測試框中顯示了測試結果,一個Failure,一個是Error。
Failure方法的錯誤描述是java.lang.AssertionError: expected:<4> but was:<5>,表示預期是4,但實際值是5.
Error的錯誤描述是java.lang.ArithmeticException: / by zero。意思是除數不能是0。
這裏寫圖片描述

    @Test
    public void testAdd() {
        assertEquals(4, new Number().add(2, 3));    //判斷2+3是不是等於4
    }

    @Test
    public void testDivision() {
        assertEquals(3, new Number().division(6, 0));   //判斷6/0是不是等於3
    }

JUnit運行流程

再次新建一個測試類,這次取名爲NumberTest2,並勾選框中的四個選項
這裏寫圖片描述
之後會自動生成代碼,需要我們手動補充,補充後的代碼如下:

public class NumberTest2 {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("beforeClass()");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        System.out.println("afterClass()");
    }

    @Before
    public void setUp() throws Exception {
        System.out.println("before()");
    }

    @After
    public void tearDown() throws Exception {
        System.out.println("after()");
    }

    @Test
    public void test() {
        System.out.println("test()");
    }

    @Test
    public void test2() {
        System.out.println("test2()");
    }

}

執行程序後查看程序執行順序
這裏寫圖片描述
從以上結果我們得出結論
1. 被@BeforeClass註解修飾的方法第一個執行
2. 被@Before註解修飾的方法會在每個@Test方法執行前執行一次
3. 被@After註解修飾的方法會在每個@Test方法執行後執行一次
4. 被@AfterClass註解修飾的方法最後一個執行
利用以上特性我們可以有效的實現初始化以及結尾清除功能

進階使用

@Test的兩個參數

@Test有兩個可控的參數,分別爲timeout和expected
新建一個測試類取名爲NumberTest3,並在裏面添加如下代碼

public class NumberTest3 {

    //第一個test()用來闡述timeout參數
    @Test(timeout=1)
    public void test() {
        while(true) {
            System.out.println("running.....");
        }
    }

    //test2()用來闡述excepted參數
    @Test(expected=ArithmeticException.class)
    public void test2() {
        assertEquals(3, new Number().division(6, 0));
    }

}

test()方法中寫入的是一個死循環,按照常理來說應該是死循環直到內存溢出,現在我們對test()進行測試,控制檯的結果是
這裏寫圖片描述
可以看到,程序自動停止了。這就是timeout參數的作用,規定程序在n毫秒之內結束,如果測試代碼沒有在n毫秒內結束,在第n毫秒時會強制停止。test()上的timeout規定在了1毫秒,所以死循環也就只執行了1毫秒。

test2()函數中寫入的是一個斷言,判斷6/0是否等於3,按照之前的測試來看,測試應該是報Error,因爲除數不能爲0,但我們加上expected之後,程序測試結果如下
這裏寫圖片描述
綠條表示測試成功。
expected參數的含義是指期望拋出什麼異常(也就是說加上這個參數後,測試的目的就變成了看它是否會拋出指定異常,如果拋出了就是綠條,沒拋出指定異常就變紅條)

測試套件

測試套件出現的目的是爲了方便我們一次運行多個類的測試。加入我們有Test1,Test2,Test3……n個測試類,我們想要全部測試他們的功能,總不可能一個類一個類的去右鍵點擊Run as junit Test吧,因此測試套件的作用就是我們可以只執行一次run as,就可以測試所有的我們想測試的類的測試方法。可以類比工具箱,我們在搬運的時候,肯定不是一件工具一件工具的來回拿放,而是把工具放在工具箱裏,一齊進行搬運。
先在test裏創建三個測試類,也就是“工具”,裏面分別有一個test方法,該方法的內容是打印函數名稱
這裏寫圖片描述
最後創建一個“工具箱”
這裏寫圖片描述
注意,這個“工具箱”類裏有如下幾個特點
1. 這整個類是個空類,什麼都不要寫,它存在的意義就僅僅只是爲了我們一次性進行多類測試
2. 兩個註解放在類名上面,且第一個註解裏的內容固定爲“Suite.class”
3. 第二個註解裏的內容是說明具體有哪些“工具”需要被一次性測試。裏面放了幾個類,就會測試幾個。

參數化設置

參數化設置的目的是方便我們進行多組數據測試。
在test裏新建一個測試類,取名MultipTest,其代碼如下


//該類必須加上註釋 @RunWith(Parameterized.class),表示這個類是參數化的測試類
@RunWith(Parameterized.class)
public class MultipTest {

//參數的類型和數量取決於test()方法,這裏因爲測試的是add()方法
//因此有一個預期值,兩個加數,總共三個參數。
    int expected = 0;
    int input1 = 0;
    int input2 = 0;


    public MultipTest(int expected,int input1, int input2) {
        this.expected = expected;
        this.input1 = input1;
        this.input2 = input2;
    }

//JUnit規定了測試數據組必須是一個靜態的collection,且裏面得是一個數組。
    @Parameters
    public static Collection<Object[]> t(){
        return Arrays.asList(new Object[][] {
            {3,1,2},
            {4,2,2}
            });
    }

    @Test
    public void testAdd() {
        assertEquals(expected, new Number().add(input1, input2));
    }

}

運行結果如圖
這裏寫圖片描述
發現有兩條數據,這兩條數據分別對應我們往collection裏放的數據。

資料參考

慕課網 JUnit單元測試
使用junit測試預期異常

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