JUnit4單元測試


一、單元測試的好處

  單元測試可以幫助我們驗證程序的邏輯是否正確、可以降低bug修復的成本、更有利於代碼重構等等。所以,我們在寫代碼的時候,盡量保證單元測試的覆蓋率。能力好的可以先寫測試用例,再寫功能代碼(測試先行)。

二、使用JUnit

  1、JUnit框架:JUnit是一個托管在Github上的開源項目,是Java程序員使用率最高的測試框架,使用@Test注釋來標識指定測試的方法。

  2、怎么在JUnit中進行測試呢(以maven項目為例):首先在pom中引入JUnit的依賴,然后在src/test/java中建立相關測試類,編寫測試用例方法,在方法上添加@Test,並在方法內使用合適的assert進行判斷,運行即可。實例如下:

public class MyTest001 {
    @Test
    public void test001(){
        Assert.assertEquals(1,1);
    }
}

  3、命名約定:

    ①在/src/test/java中建立與/src/main/java相對應的測試類,以Test為后綴。

    ②測試名稱應該見名知意,一般使用多should、when、then等單詞。

  4、JUnit4中常用的注釋

@Test 將方法標識為測試方法,還可以有expected和timeout兩個屬性
@Test(expected = Exception.class) 如果方法不拋出指定的異常,則失敗
@Test(timeout = 100) 如果方法花費的時間超過100毫秒,則會失敗
@Before 在測試方法執行之前,先執行被@Before標記的方法,用於准備測試環境,如初始化類等。
@After 在測試方法執行之后執行,用於清理測試環境,如刪除臨時數據等。
@BeforeClass 在所有測試開始之前執行一次,用於執行時間密集型活動,如數據庫連接。被@BeforeClass標記的方法需要是static修飾
@AfterClass 在所有測試完成后執行一次。用於執行清理活動,如斷開與數據庫的連接。被@AfterClass標記的方法需要是static修飾
@Ignore 標記應禁用測試。當底層代碼已更改且測試用例尚未調整時,非常有用。最好描述禁用原因。

代碼示例:

public class MyTest001 {

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

    @Before
    public void before(){
        System.out.println("MyTest001.before...");
    }

    @Test
    public void test001(){
        System.out.println("MyTest001.test001...");
        Assert.assertEquals(1,1);
    }

    @Test
    @Ignore("測試用例沒有修改...")
    public void test002(){
        System.out.println("MyTest001.test002...");
        Assert.assertEquals(1,1);
    }

    @After
    public void after(){
        System.out.println("MyTest001.after...");
    }

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

}

 運行結果如下:

    

  5、JUnit4斷言

    JUnit通過Assert類提供的靜態方法來測試某些條件。這些斷言語句通常是以assert開頭。可以指定錯誤信息、預期結果和實際結果。斷言方法將測試返回的實際值和預期值進行比較。如果比較失敗,將拋出java.lang.AssertionError異常。

    常用斷言如下,[message]參數可選:

fail([String message]) 讓測試方法失敗。
assertTrue([String message,] boolean condition) 檢查布爾條件是否為true。對應方法名稱assertFalse

assertEquals([String message,] 多種類型 unexpected,
多種類型 actual)

測試兩個值是否相同。對應方法名稱assertNotEquals。

assertEquals([String message,] double/float expected,
double/float actual, double/float delta)

測試float或double值是否匹配。容差是必須相同的小數位數。對應方法名稱assertNotEquals。
assertNull([String message,] Object object) 檢查對象是否為空。對應方法名稱assertNotNull。
assertSame([String message,]Object expected, Object actual) 檢查兩個變量是否引用同一個對象。對應方法名稱assertNotSame

assertArrayEquals([String message,] 各種類型[] expecteds,
各種類型[] actuals)

檢查數組內容是否相同。

assertArrayEquals([String message,] double/float[] expecteds,
double/float[] actuals, double/float delta)

檢查double/float數組內容是否相同,指定容差范圍。

assertThat([String message, ]T actual, Matcher matcher)

actual為需要測試的變量,matcher為使用Hamcrest的匹配符來表達變量actual期望值的聲明。(其實內部調用的是org.hamcrest.MatcherAssert.assertThat)

  

  6、測試類中測試方法的執行順序

    測試類中的測試方法,也是可以指定按方法名稱的字典順序執行的,在測試類上添加@FixMethodOrder注解,有三個值可選分別是:MethodSorters.DEFAULT:默認執行順序,由方法名hashcode值來決定,如果hash值大小一致,則按名字的字典順序確定;MethodSorters.NAME_ASCENDING:按方法名稱的字典順序;MethodSorters.JVM:按JVM返回的方法名的順序執行。示例代碼如下:

/**
 * @FixMethodOrder指定測試方法執行順序
 * MethodSorters.DEFAULT:默認執行順序,由方法名hashcode值來決定,如果hash值大小一致,則按名字的字典順序確定。
 * MethodSorters.NAME_ASCENDING:按方法名稱的字典順序。
 * MethodSorters.JVM:按JVM返回的方法名的順序執行。
 */
@FixMethodOrder(MethodSorters.JVM)
public class MyTest003 {

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

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

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

}

運行結果:MethodSorters.DEFAULT        

     MethodSorters.NAME_ASCENDING   

     MethodSorters.JVM          

  7、JUnit測試套件

    我們可以將幾個測試類組合到一個測試套件中,根據填寫的順序運行測試類。

/**
 * 使用@Suite.SuiteClasses可以將多個測試類放到一起進行測試,也可以包含其他被@Suite.SuiteClasses標記的類
 * 以指定的順序運行套件中的所有測試類。
 */
@RunWith(Suite.class)
@Suite.SuiteClasses({MyTest001.class,MyTest002.class,MyTest003.class})
public class AllTests {
}

  8、分類測試

    我們還可以定義測試類別,並根據注釋包含或排除它們。

public interface FastTests {
    /* 類別標記 */
}

public interface SlowTests {
    /* 類別標記 */
}

public class A {

    @Test
    public void a() {
        fail();
    }

    /**
     * 該方法屬於SlowTests類別
     */
    @Test
    @Category(SlowTests.class)
    public void b() {
    }

}

/**
 * 該測試類屬於SlowTests、FastTests兩種類別
 */
@Category({SlowTests.class, FastTests.class})
public class B {

    @Test
    public void c() {
    }
}

/**
 * 分類別運行測試用例
 */
@RunWith(Categories.class)
@Categories.IncludeCategory(SlowTests.class)  //指定包含的類別
@Categories.ExcludeCategory(FastTests.class) //指定排除的類別
@Suite.SuiteClasses( { A.class, B.class }) // 類別是一種套件
public class SlowTestSuite {
    // 不打開注釋@Categories.ExcludeCategory,將會運行 A.b and B.c, 不會運行 A.a
    // 打開注釋@Categories.ExcludeCategory,將會運行 A.b
}

  8、JUnit參數化測試:https://github.com/Pragmatists/JUnitParams

  9、JUnit規則:https://github.com/junit-team/junit4/wiki/Rules

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM