JUnit是最流行的開源Java單元測試工具,目前它的穩定版是4.12版。JUnit 4是2005年推出的,它基於Java 5的注釋、反射等特性開發,距今已經超過十年了,受目前Java 8以及Lambda表達式等的影響,JUnit團隊決定推出JUnit 5版。
目前JUnit 5已經推出了5.0.0 Alpha版,見: https://t.co/Mb12F3WF4A
JUnit 5完全使用當前的Java 8重寫了所有代碼,因此JUnit 5的運行條件是Java 8環境。
JUnit 5允許在斷言中使用Lambda表達式,這個特性可以從開源的斷言庫AssertJ中可以看到。
AssertJ庫見: http://joel-costigliola.github.io/assertj/
與JUnit 4不同,JUnit 5不再是單個庫,而是模塊化結構的集合,整個API分成了:自己的模塊、引擎、launcher、針對Gradle和Surefire的集成模塊。
JUnit團隊還發起了名為Open Test Alliance for the JVM的活動,見: https://github.com/ota4j-team/opentest4j
JUnit 5的測試看上去與JUnit 4相同:同樣是創建類,添加測試方法,使用@Test注釋。但是,JUnit 5還提供了全新的一套注釋集合,而且斷言方法從JUnit 4的org.junit.Assert包移到了JUnit 5的org.junit.gen5.api.Assertions包。比如:
import org.junit.gen5.api.Assertions;
import org.junit.gen5.api.Test;
public class Test1 {
@Test
public void test() {
Assertions.assertEquals(3 * 6, 18);
Assertions.assertTrue(5 > 4);
}
}
JUnit 5的斷言方法與JUnit 4相似,斷言類提供了assertTrue、assertEquals、assertNull、assertSame以及相反的斷言方法。不同之處在於JUnit 5的斷言方法支持Lambda表達式。而且還有一個名為分組斷言(Grouped Assertions)的新特性。
分組斷言允許執行一組斷言,且會一起報告。要記得在JUnit 4中,我們被告誡不要在一個測試中放入多個斷言,以避免某些斷言沒有得到執行。現在,在JUnit 5中使用分組斷言就無需再顧慮這個避諱了。
對JUnit 4的另一個改進是斷言預期的異常。不再是以前那種把預期的異常類型放入@Test注釋,或者是用try-catch包裹代碼,JUnit 5使用assertThrows和equalsThrows斷言。下面看看斷言的例子:
public class Test2 {
@Test
public void lambdaExpressions() {
// lambda expression for condition
assertTrue(() -> "".isEmpty(), "string should be empty");
// lambda expression for assertion message
assertEquals("foo", "foo", () -> "message is lazily evaluated");
}
@Test
public void groupedAssertions() {
Dimension dim = new Dimension(800, 600);
assertAll("dimension",
() -> assertTrue(dim.getWidth() == 800, "width"),
() -> assertTrue(dim.getHeight() == 600, "height"));
}
@Test
public void exceptions() {
// assert exception type
assertThrows(RuntimeException.class, () -> {
throw new NullPointerException();
});
// assert on the expected exception
Throwable exception = expectThrows(RuntimeException.class, () -> {
throw new NullPointerException("should not be null");
});
assertEquals("should not be null", exception.getMessage());
}
}
假設、標簽和禁止測試是JUnit 4的特性,在JUnit 5中仍然得以保留。不同的是假設中也支持Lambda表達式,假設的思想是如果假設條件沒有得到滿足,那麼跳過測試執行。標簽Tags等同於JUnit 4的測試分類的概念,可以對測試類和方法進行分類。JUnit 4禁止測試使用了@Ignore注釋,而在JUnit 5中則使用@Disabled注釋。
public class Test3 {
@Test
@Disabled
public void disabledTest() {
// ...
}
@Test
@Tag("jenkins")
public void jenkinsOnly() {
// ...
}
@Test
public void windowsOnly() {
Assumptions.assumeTrue(System.getenv("OS").startsWith("Windows"));
// ...
}
}
JUnit 5提供了一套新的擴展API,取代了以前的@RunWith和@Rule擴展機制。JUnit 4的測試類被限制到僅有一個Runner上,而新的擴展模型則允許一個類或方法keyii注冊到多種擴展。
@ExtendWith(MockitoExtension.class)
@ExtendWith(CdiUnitExtension.class)
public class Test4 {
@Test
@DisplayName("awesome test")
void dependencyInjection(TestInfo testInfo) {
assertEquals("awesome test", testInfo.getDisplayName());
}
}
JUnit 5內建的擴展還支持方法級的依賴注入。
JUnit 5支持Hamcrest匹配和AssertJ斷言庫,可以用它們來代替JUnit 5的方法。
public class Test5 {
@Test
public void emptyString() {
// JUnit 5
org.junit.gen5.api.Assertions.assertTrue("".isEmpty());
// AssertJ
org.assertj.core.api.Assertions.assertThat("").isEmpty();
// Hamcrest
org.hamcrest.MatcherAssert.assertThat("", isEmptyString());
}
}
JUnit 5的主頁見: https://github.com/junit-team/junit5
有興趣的朋友可以關注。