開發與維運

Java程序員必須要知道的單元測試框架Junit詳解

一、為什麼需要單元測試


在平時的開發當中,一個項目往往包含了大量的方法,可能有成千上萬個。如何去保證這些方法產生的結果是我們想要的呢?當然了,最容易想到的一個方式,就是我們通過System.out來輸出我們的結果,看看是不是滿足我們的需求,但是項目中這些成千上萬個方法,我們總不能在每一個方法中都去輸出一遍嘛。這也太枯燥了。這時候用我們的單元測試框架junit就可以很好地解決這個問題。

junit如何解決這個問題的呢?答案在於內部提供了一個斷言機制,他能夠將我們預期的結果和實際的結果進行比對,判斷出是否滿足我們的期望。相信到這,你已經迫不及待的想認識一下junit,下面我們直接通過案例,來分析一下這個機制。

二、從案例講起


1、預備工作


junit4是一個單元測試框架,既然是框架,這也就意味著jdk並沒有為我們提供api,因此在這裡我們就需要導入相關的依賴。對於IDEA來說,你在構建Maven項目的時候會直接自動添加相關的依賴,如果沒有,手動添加即可:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

這裡的版本是4.12。當然還有最新的版本。你可以手動選擇。這裡選用的是4的版本。

2、案例


這裡我們要測試的功能超級簡單,就是加減乘除法的驗證。

public class Calculate {
    public int add(int a,int b) {
        return a + b;
    }
    public int subtract(int a, int b) {
        return a - b;
    }
    public int multiply(int a,int b) {
        return a * b;
    }
    public int divide(int a ,int b) {
        return a / b;
    }
}

然後我們看看如何使用junit去測試。

public class CalculateTest {
    @Test
    public void testAdd() {
        assertEquals(2, new Calculate().add(1,1));
    }
    @Test
    public void testSubtract() {
        assertEquals(8, new Calculate().subtract(10,2));
    }
    @Test
    public void testMultiply() {
        assertEquals(6, new Calculate().multiply(3, 2));
    }
    @Test
    public void testDivide() {
        assertEquals(5, new Calculate().divide(10, 2));
    }
}

以上就是我們的單元測試,需要遵循一下規則:

1、每一個測試方法上使用@Test進行修飾

2、每一個測試方法必須使用public void 進行修飾

3、每一個測試方法不能攜帶參數

4、測試代碼和源代碼在兩個不同的項目路徑下

5、測試類的包應該和被測試類保持一致

6、測試單元中的每個方法必須可以獨立測試

以上的6條規則,是在使用單元測試的必須項,當然junit也建議我們在每一個測試方法名加上test前綴,表明這是一個測試方法。

assertEquals是一個斷言的規則,裡面有兩個參數,第一個參數表明我們預期的值,第二個參數表示實際運行的值。不過junit5對這些做出了一些改變,我們會在後續的文章中專門介紹。

我們運行一下測試類,就會運行每一個測試方法,我們也可以運行某一個,只需要在相應的測試方法上面右鍵運行即可。如果運行成功編輯器的控制檯不會出現錯誤信息,如果有就會出現failure等信息。

3、運行流程


在上面的每一個測試方法中,代碼是相當簡單的,就一句話。現在我們分析一下這個測試的流程是什麼:

public class JunitFlowTest {
    @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 test1() {
        System.out.println("test1方法...");
    }
    @Test
    public void test2(){
        System.out.println("test2方法...");
    }
}

在上面的代碼中,我們使用了兩個測試方法,還有junit運行整個流程方法。我們可以運行一下,就會出現下面的運行結果:

beforeClass...
before...
test1方法...
after
before...
test2方法...
after
afterClass...

從上面的結果我們來畫一張流程圖就知道了:

v2-1f3cf14e36c2182cb759f69ff38b9364_1440w.jpg

這個流程相信應該能看懂,如果我們使用過SSM等其他的一些框架,經常會在before中添加打開數據庫等預處理的代碼,也會在after中添加關閉流等相關代碼。

以上這個案例如果能看懂,基本上算是入門了。其實這個案例也比較簡單。相信以大家聰明的頭腦能看懂。下面我們看看junit中的註解。

三、註解


對於@Test,裡面有很多參數供我們去選擇。我們來認識一下

1、@Test(expected=XX.class)


這個參數表示我們期望會出現什麼異常,比如說在除法中,我們1/0會出現ArithmeticException異常,那這裡@Test(expected=ArithmeticException.class)。在測試這個除法時候依然能夠通過。

2、@Test(timeout=毫秒 )


這個參數表示如果測試方法在指定的timeout內沒有完成,就會強制停止。

3、@Ignore


這個註解其實基本上不用,他的意思是所修飾的測試方法會被測試運行器忽略。

4、@RunWith

更改測試運行器。

四、測試套件


在文中一開始我們曾經提到,如果我們的項目中如果有成千上萬個方法,那此時也要有成千上萬個測試方法嘛?如果這樣junit使用起來還不如System.out呢,現在我們認識一下測試嵌套的方法,他的作用是我們把測試類封裝起來,也就是把測試類嵌套起來,只需要運行測試套件,就能運行所有的測試類了。、

//這裡有很多個測試類
public class Test1 {
    @Test
    public void test() {
        System.out.println("測試類1");
    }
}
public class Test2 {
    @Test
    public void test() {
        System.out.println("測試類2");
    }
}
//這裡一次可以類推

下面我們使用測試套件,把這些測試類嵌套在一起。

@RunWith(Suite.class)
@Suite.SuiteClasses({Test1.class,Test2.class等相關測試類})
public class SuiteTest {
    /*
     * 寫一個空類:不包含任何方法
     * 更改測試運行器Suite.class
     * 將測試類作為數組傳入到Suite.SuiteClasses({})中
     */
}

也很簡單,下面我們看一下,參數化設置。

五、參數化設置


什麼是參數化設置呢?在一開始的代碼中我們看到,測試加法的時候是1+1,不過我們如果要測試多組數據怎麼辦?總不能一個一個輸入,然後運行測試吧。這時候我們可以把我們需要測試的數據先配置好。

@RunWith(Parameterized.class)
public class ParameterTest {
    int expected =0;
    int input1 = 0;
    int input2 = 0;
    @Parameters
    public static Collection<Object[]> t() {
        return Arrays.asList(new Object[][]{
                {3,1,2},
                {4,2,2}
        }) ;
    }
    public ParameterTest(int expected,int input1,int input2) {
        this.expected = expected;
        this.input1 = input1;
        this.input2 = input2;
    }
    @Test
    public void testAdd() {
        assertEquals(expected, new Calculate().add(input1, input2));
    }
}

這時候再去測試,只需要去選擇相應的值即可,避免了我們一個一個手動輸入。

對於junit測試,常用的使用方法就是這麼多,關於深入瞭解,只能放在後面的課程中了。今天先到這。

Leave a Reply

Your email address will not be published. Required fields are marked *