Demo002 IDEA中Junit單元測試的使用(初級篇)

推薦JUnit視頻教程:JUnit—Java單元測試必備工具html

1.基本理論

1.1 單元測試

單元測試又稱模塊測試,屬於白盒測試,是最小單位的測試。模塊分爲程序模塊和功能模塊。功能模塊指實現了一個完整功能的模塊(單元),一個完整的程序單元具有輸入、加工和輸出三個環節。並且每一個程序單元都應該有正規的規格說明,使之對其輸入、加工和輸出的關係作出名明確的描述。java

JUnit是一個迴歸測試框架(regression testing framework)。Junit測試是程序員測試,即所謂白盒測試,由於程序員知道被測試的軟件如何(How)完成功能和完成什麼樣(What)的功能。Junit是一套框架,繼承TestCase類,就能夠用Junit進行自動測試了。git

1.2 什麼是Junit

①JUnit是用於編寫可複用測試集的簡單框架,是xUnit的一個子集。xUnit是一套基於測試驅動開發的測試框架,有PythonUnit、CppUnit、JUnit等。程序員

②Junit測試是程序員測試,即所謂白盒測試,由於程序員知道被測試的軟件如何(How)完成功能和完成什麼樣(What)的功能。編程

③多數Java的開發環境都已經集成了JUnit做爲單元測試的工具,好比IDEA,Eclipse等等。框架

④JUnit官網:Junitmaven

1.3 爲何要使用單元測試

①測試框架能夠幫助咱們對編寫的程序進行有目的地測試,幫助咱們最大限度地避免代碼中的bug,以保證系統的正確性和穩定性。編程語言

②不少人對本身寫的代碼,測試時就簡單寫main,而後sysout輸出控制檯觀察結果。這樣很是枯燥繁瑣,不規範。缺點:測試方法不能一塊兒運行,測試結果要程序猿本身觀察才能夠判斷程序邏輯是否正確。編輯器

③JUnit的斷言機制,能夠直接將咱們的預期結果和程序運行的結果進行一個比對,確保對結果的可預知性。ide

1.4 測試覆蓋

評測測試過程當中已經執行的代碼的多少。

1.5 代碼覆蓋率

代碼的覆蓋程度,一種度量方式。針對代碼的測試覆蓋率有許多種度量方式。

  • 語句覆蓋( StatementCoverage ):也稱爲行覆蓋( lin EC overage ) , 段覆蓋(segmentcoverage)和基本塊覆蓋(bASicblockcoverage)。它度量每個可執行語句是否被執行到了。

  • 斷定覆蓋(DecisionCoverage):也被稱爲分支覆蓋(branchcoverage),全部邊界覆蓋(alledgescoverage), 基本路徑覆蓋( basispathcoverage ), 斷定路徑覆蓋(decisiondecisionpath或DDPtesting)。它度量是否每一個 BOOL 型的表達式取值true 和 false 在控制結構中都被測試到了。

  • 條件覆蓋(ConDItionCoverage): 它獨立的度量每個子表達式,報告每個子表達式的結果的 true 或 false。這個度量和斷定覆蓋(decisioncoverage)類似,可是對控制流更敏感。不過,徹底的條件覆蓋並不能保證徹底的斷定覆蓋。

  • 路徑覆蓋(PathCoverage):也稱爲斷言覆蓋(prEDIcatecoverage),它度量了是否函數的每個可能的分支都被執行了。路徑覆蓋的一個好處是:須要完全的測試。但有兩個缺點:一是,路徑是以分支的指數級別增長的,例如:一個函數包含 10個 IF 語句,就有 1024 個路徑要測試。若是加入一個 IF 語句,路徑數就達到 2048;二是,許多路徑不可能與執行的數據無關。

  • 循環覆蓋(LOOPCoverage):這個度量報告你是否執行了每一個循環體零次、只有一次仍是多餘一次(連續地)。對於 dowhile循環,循環覆蓋報告你是否執行了每一個循環體只有一次仍是多餘一次(連續地)。這個度量的有價值的方面是肯定是否對於 while 循環和 for 循環執行了多於一次,這個信息在其它的覆蓋率報告中是沒有的。

2. IDEA中Junit 4的配置

2.1 環境配置

IDEA中自帶JUnit的jar包(hamcrest-core-1.3.jarjunit.jarjunit-4.12.jar):位於安裝目錄下的lib文件內。即:IntelliJ IDEA 2018.1\lib

IDEA自帶一個JUnit插件, 該插件能夠運行JUnit測試文件,但沒法自動生成JUnit測試代碼. 若是須要自動生成測試代碼,須要安裝JUnitGenerator V2.0 插件。

安裝方法:File-->settings-->Plguins-->Browse repositories-->輸入JUnit-->選擇JUnit Generator V2.0安裝,安裝好後重啓 IDEA,便可使用。

PS: IDEA自帶的JUnit插件和JUnitGeneratorV2.0插件都要勾選上,若只勾選JUnit可能致使沒法自動生成測試文件,若只勾選JUnitGenerator V2.0可能致使生成的測試文件沒法運行

2.2 修改配置

  1. 經過模版生成的測試代碼與java類在同一個目錄下,與maven項目標準測試目錄不匹配。修改方法:
    ${SOURCEPATH}/test/${PACKAGE}/${FILENAME} 修改成${SOURCEPATH}/../test/java/${PACKAGE}/${FILENAME}
    有時候會出現一個提示框,提示選擇(general/merge/exixt),選擇general就行

    ${SOURCEPATH} 原類的路徑,就是你本身寫的類
    ${PACKAGE} 原類的包名,java包命名規範就是按照包名一級一級建立的文件夾
    ${filename} 測試類的類名

  2. 修改 Junit4 選項卡中包的申明,把默認的 test 前綴去掉。

  3. 生成的測試文件@since位置Date可能存在亂碼,可配置JUnit模板更改日期格式,不影響程序可直接忽略。修改方法:
    第40行:@since <pre>$Date</pre> 修改成
    @since <pre>$today</pre>

3. 簡單入門單元測試

婁老師的博客文章中講了單元測試,咱們根據老師的方法來進行簡單入門單元測試。

什麼是單元測試?單元測試(unit testing),是指對軟件中的最小可測試單元進行檢查和驗證。對於單元測試中單元的含義,通常來講,要根據實際狀況去斷定其具體含義,如Java裏單元指一個類。

編程是智力活動,不是打字,編程前要把幹什麼、如何幹想清楚才能把程序寫對、寫好。與目前很多同窗一說編程就打開編輯器寫代碼不一樣,我但願同窗們養成一個習慣,當大家想用程序解決問題時,要會寫三種碼:

  • 僞代碼
  • 產品代碼
  • 測試代碼

僞代碼與具體編程語言無關,不要寫與具體編程語言語法相關的語句(如用malloc分配內存,這樣只能用C語言編程了),僞代碼從意圖層面來解決問題,最終,僞代碼產品代碼最天然的、最好的註釋。

需求:咱們要在一個Calculator類中來實現簡單計算器的功能。

3.1 僞代碼

設計的僞代碼:

簡單計算器:
    
    加法:返回兩個數相加後的結果
    
    減法:返回兩個數相減後的結果
    
    乘法:返回兩個數相乘後的結果
    
    除法:除數不爲0,返回兩個數相除後的結果
    
        除數爲0,打印異常信息在程序中出錯的位置及緣由
        
    其餘 :未完成的模塊例如平方、開方等等

3.2 產品代碼

有了僞代碼,用特定語言翻譯一下,就是可用的產品代碼了。
翻譯以後的產品代碼Calculator.java

public class Calculator {
    public int add(int x, int y) { //加法
        return x + y;
    }

    public int sub(int x, int y) { //減法
        return x - y;
    }

    public int mul(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) { //未完成的模塊:例如平方、開方等等
        //還在開發中
    }


//    public static void main(String[] args) { // 傳統代碼測試
//        int a = 8;
//        int b = 2;
//        Calculator calculator = new Calculator();
//        System.out.println(calculator.add(a, b));
//        System.out.println(calculator.sub(a, b));
//        System.out.println(calculator.mul(a, b));
//        System.out.println(calculator.div(a, b));
//        System.out.println(calculator.div2(a,0));
//    }
}

在IDEA中建立項目unitTask01,在src 右鍵新建java類com.ryanjie.junit01.Calculator,將上述代碼寫入。

3.3 測試代碼

寫了產品代碼,咱們還要寫測試代碼,證實本身的代碼沒有問題。

Java編程時,程序員對類實現的測試叫單元測試。類XXXX的單元測試,咱們通常寫建一個XXXXTest的類。

因此,對於Calculator類,咱們寫一個CalculatorTest.java的測試模塊,代碼以下:

public class CalculatorTest {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        
        if (calculator.add(8, 2) == 10) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.sub(8, 2) == 6) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.mul(8, 2) == 16) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.div(8, 2) == 4) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }
    }
}

這裏咱們設計了一個測試用例(Test Case),測試用例是爲某個特殊目標而編制的一組測試輸入、執行條件以及預期結果,以便測試某個程序路徑或覈實是否知足某個特定需求。這裏咱們的測試輸入8和2的加減乘除四種運算,預期結果分別爲10,6,16,4

咱們在Calculator類上單擊鼠標右鍵,在彈出的菜單中選擇Generate(咱們能夠看到對應鍵盤快捷鍵爲Alt+Insert)-> Junit Test -> Junit 4,這時IDEA會自動生成一個test目錄並生成CalculatorTest類,咱們先刪除自動生成的代碼,輸入剛纔寫的CalculatorTest.java代碼。

在 IDEA中咱們把產品代碼放在src目錄中,把測試代碼放在test目錄中,在命令行中咱們知道要設置SOURCEPATH環境變量,在IDEA中咱們右鍵單擊test目錄,在彈出的菜單中選擇Mark Directory as->Test Sources Root就能夠了:(這時test文件夾圖標會變綠)

在IDEA中運行結果以下,測試結果符合預期:

3.4 測試代碼2 (使用Junit)

在剛纔自動生成的test目錄下,CalculatorTest.java裏代碼以下:

public class CalculatorTest {

    @Before
    public void before() throws Exception {
    }

    @After
    public void after() throws Exception {
    }

    /**
     *
     * Method: add(int x, int y) 
     *
     */
    @Test
    public void testAdd() throws Exception {
    }

    /**
     *
     * Method: sub(int x, int y) 
     *
     */
    @Test
    public void testSub() throws Exception {
    }

    /**
     *
     * Method: mul(int x, int y) 
     *
     */
    @Test
    public void testMul() throws Exception {
 
    }

    /**
     *
     * Method: div(int x, int y) 
     *
     */
    @Test
    public void testDiv() throws Exception {
    }

    /**
     *
     * Method: div2(int x, int y) 
     *
     */
    @Test
    public void testDiv2() throws Exception {
    }

    /**
     *
     * Method: loop(int x, int y) 
     *
     */
    @Test
    public void testLoop() throws Exception {
    }

    /**
     *
     * Method: unCompleted(int x, int y) 
     *
     */
    @Test
    public void testUnCompleted() throws Exception {
    }

}

咱們修改CalculatorTest.java測試模塊,代碼以下:

public class CalculatorTest {
    Calculator calculator;

    @Before
    public void setUp() throws Exception {
        calculator = new Calculator();
    }

    @After
    public void after() throws Exception {
    }

    /**
     *
     * Method: add(int x, int y)
     *
     */
    @Test
    public void testAdd() throws Exception {
        Assert.assertEquals(calculator.add(8,2),10);
    }

    /**
     *
     * Method: sub(int x, int y)
     *
     */
    @Test
    public void testSub() throws Exception {
        Assert.assertEquals(calculator.sub(8,2),6);
    }

    /**
     *
     * Method: mul(int x, int y)
     *
     */
    @Test
    public void testMul() throws Exception {
        Assert.assertEquals(calculator.mul(8,2),16);
    }

    /**
     *
     * Method: div(int x, int y)
     *
     */
    @Test
    public void testDiv() throws Exception {
        Assert.assertEquals(calculator.div(8,2),4);
    }

    /**
     *
     * Method: div2(int x, int y)
     *
     */
    @Ignore
    public void testDiv2() throws Exception {
    }

    /**
     *
     * Method: loop(int x, int y)
     *
     */
    @Ignore
    public void testLoop() throws Exception {
    }

    /**
     *
     * Method: unCompleted(int x, int y)
     *
     */
    @Ignore
    public void testUnCompleted() throws Exception {
    }

}

在IDEA中運行結果以下,測試結果符合預期:

3.5 編輯測試設置

咱們能夠經過Run ->Edit Configuration或工具欄上的標籤來調整咱們測試運行配置:

Configuration選項卡,用戶能夠選擇須要運行的測試。例如,您能夠從一個類、程序包、測試套件或甚至模式中運行全部的測試。這裏的Fork模式讓用戶在一個單獨的進程運行每一個測試。

代碼覆蓋測試:

  • 默認狀況下使用本身的測試引擎
  • 覆蓋率模式:Tracing會增長消耗,可是測試會更準確

3.6 收集覆蓋率

Run ->Run 'MyClassTest' with Coverage或工具欄上的選項運行特定模式的測試。

當覆蓋模式運行至少一個測試以後,IDE將會在Project工具窗口顯示每一個程序包、類的覆蓋率數據,同時在Coverage工具窗和編輯器中也會顯示。

若是用戶添加另外一個方法到junit01,並運行覆蓋率測junit01,就會發現,沒有被測試覆蓋到的代碼都將高亮顯示爲紅色。覆蓋的代碼顏色則是綠色。若是一些代碼是隻覆蓋部分,那沒將顯示爲黃色。

本文代碼:UnitTask01

相關文章
相關標籤/搜索