天天看點

JUnit 4 簡介

JUnit4

是一個易學易用的Java單元測試架構,使用非常廣泛。現階段的最新版本号是4.12,JUnit5目前正在測試中,是以這裡還是以JUnit4為準。

引入JUnit

現在主流的IDE比如IDEA或者Eclipse都提供了對JUnit4的支援,可以非常友善的使用JUnit4。當你在代碼中添加了@Test注解,然後使用IDE的自動補全功能時,一般情況下IDE會彈出對話框詢問你是否将JUnit4庫添加到項目的類路徑下。

當然也可以自己手動添加JUnit4的依賴。如果使用Maven,添加如下一段:

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

如果使用Gradle,添加如下一段:

testCompile group: 'junit', name: 'junit', version: '4.12'
           

使用以上這些建構工具還有一個好處就是可以指定作用域,在上面我們将JUnit的作用域指定為測試時期,也就是說當我們實際釋出代碼的時候并不會包含JUnit的包。

基本使用

下面示範了JUnit的基本使用方法。

public class AppTest {
    private User user;

    @Before
    public void init() {
        user = new User();
        user.setId(1);
        user.setUsername("yitian");
        user.setPassword("1234");
        user.setBirthday(LocalDate.now());
    }

    @Test
    public void testBean() {
        Assert.assertNotNull(user);
    }
}
           

要讓一個方法變成測試方法,隻需要向其添加@Test注解即可。在測試方法中我們可以使用傳統的

System.out.println

方法來輸出,也可以使用各種日志架構來列印日志。還可以使用幾個注解來初始化和清理測試方法用到的資料。Before和After注解會在每個測試方法之前和之後調用。BeforeClass和AfterClass注解會在所有測試方法之前和之後調用。這兩個方法實際上是作為靜态方法使用的,是以初始化的資料必須定義為靜态的。由于名字上可能引起混淆,是以在JUnit5中後兩個注解重新命名為BeforeEach和AfterEach。

public class AppTest {
    private static Connection connection;


    @BeforeClass
    public static void init() throws SQLException {
        connection = DriverManager.getConnection("jdbc:mysql///test");
    }

    @AfterClass
    public static void clean() throws SQLException {
        connection.close();
    }

    @Test
    public void testBean() {
        Assert.assertNotNull(connection);
    }
}
           

定義好測試方法之後,就可以測試了。在IDEA中,直接點選測試類旁邊的綠色箭頭即可運作。如果在Eclipse中,需要點選運作按鈕,然後選擇作為JUnit運作。

斷言

除了在測試方法中使用輸出語句之外,還可以使用JUnit提供的斷言,來判斷程式是否符合某個條件,如果斷言為真,測試通過,如果斷言為假,測試失敗。斷言在

org.junit.Assert

類中,有一組以assert開頭的方法用于斷言測試,基本上涵蓋了大部分需求。下面列舉幾個常用的,如果有需要的話可以直接調用assertFail方法讓斷言直接失敗。

斷言方法 作用
assertTrue 真值斷言
assertFalse 假植斷言
assertEquals 相等斷言
assertNotEquals 不等斷言
assertNull 空值斷言
assertNotNull 非空值斷言
assertFail 斷言失敗

有了這些斷言,就可以友善地測試了。我們可以建立一個對象,然後調用這些斷言,将對象的實際狀态和我們的預期結果進行比較,如果斷言失敗,我們就知道什麼地方出現了問題。

使用Matchers

除了使用基本的斷言,還可以使用Matchers進行更友善自然的測試。假如我們要測試一個字元串是否包含color或者colour。使用普通斷言如下:

assertTrue(responseString.contains("color") || responseString.contains("colour"));
// ==> failure message: 
// java.lang.AssertionError:
           

如果使用Matchers的話就像這樣:

assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
// ==> failure message:
// java.lang.AssertionError: 
// Expected: (a string containing "color" or a string containing "colour")
// got: "Please choose a font"
           

可以看到,不論是文法還是測試輸出,使用Matcher都更加易讀。JUnit官方還列舉了幾個例子,從中我們就可以看到使用Matchers的友善之處。

assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));
           

要使用Matchers,需要使用

org.junit.Assert

類的assertThat方法,然後将要斷言的對象和Matcher謂語參數傳入。又細心的同學可能會發現如果使用Maven或者Gradle,添加了JUnit的話會同時包含另一個依賴項Hamcrest,這個包中就定義着大量謂語,可以讓我們友善的進行測試。詳細情況請參見

Hamcrest的Java文檔

忽略測試

要忽略某個測試,隻需要在測試方法上添加Ignore注解,還可以使用一個可選的字元串說明忽略測試的原因。

@Ignore("Test is ignored as a demonstration")
@Test
public void testSame() {
    assertThat(1, is(1));
}
           

測試的逾時

針對可能耗費大量時間的測試,還可以為測試設定一個時間,如果超過該時間測試直接失敗。

要為某一個測試方法設定逾時,在Test注解時傳入timeout參數,機關是毫秒:

@Test(timeout=1000)
public void testWithTimeout() {
  ...
}
           

要為某個測試類中的所有方法設定逾時,需要在測試類中添加一個

org.junit.rules.Timeout

的字段并用@Rule注解。

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

public class HasGlobalTimeout {
    public static String log;
    private final CountDownLatch latch = new CountDownLatch(1);

    @Rule
    public Timeout globalTimeout = Timeout.seconds(10); // 10 seconds max per method tested

    @Test
    public void testSleepForTooLong() throws Exception {
        log += "ran1";
        TimeUnit.SECONDS.sleep(100); // sleep for 100 seconds
    }

    @Test
    public void testBlockForever() throws Exception {
        log += "ran2";
        latch.await(); // will block 
    }
}
           

與其他架構的內建

這個特性得益于JUnit的運作器機制,它允許第三方軟體建立運作器,以自己的方式運作JUnit測試。如果在一個普通項目中,我們可以使用IDE提供的運作測試功能來運作測試,IDE會為我們生成圖形化的運作結果,用顔色來區分測試的成功與否。如果使用Mavne或Gradle,我們可以使用這些工具提供的測試指令來運作所有測試,生成測試結果。

Spring也提供了自己的運作器。如果在Spring項目中我們可以通過添加@RunWith注解并使用Spring運作器,這樣測試類就會運作在Spring環境中,我們可以使用Spring的依賴注入将測試對象直接注入到測試類中。當然其他的Spring架構特性也支援。

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
    @Autowired
    private User user;
    @Test
    public void testBean() {
    }

}
           

以上就是JUnit4 單元測試架構的一些簡單使用。詳細情況可以參見它的

官方網站

。另外JUnit5已經進入Milestone版本了,相信正式版也不遠了。等到JUnit5正式版出來時,我在為大家介紹新版JUnit的使用方法。

參考資料

https://github.com/junit-team/junit4/wiki/Matchers-and-assertthat https://github.com/junit-team/junit4/wiki/Ignoring-tests https://github.com/junit-team/junit4/wiki/Timeout-for-tests