JUnit 5學習心得
JUnit 5簡介
與之前的版本不同,JUnit 5 由三個不同的模塊組成规婆。第一個模塊是 JUnit 平臺泽裳,其主要作用是在 JVM 上啟動測試框架。它定義了一個抽象的 TestEngine API 來定義運行在平臺上的測試框架黔酥,同時還支持通過命令行藻三、Gradle 和 Maven 來運行平臺。
JUnit 5 對 Java 運行環(huán)境的最低要求是 Java 8跪者】妹保可以在 Eclipse 和 IntelliJ IDEA 上運行 JUnit 5 測試。
JUnit 5新更新
JUnit 5允許在斷言中使用Lambda表達式(Lambda表達式是Java SE 8中一個重要的新特性渣玲。lambda表達式允許你通過表達式來代替功能接口逗概。 lambda表達式就和方法一樣,它提供了一個正常的參數(shù)列表和一個使用這些參數(shù)的主體(body,可以是一個表達式或一個代碼塊。Lambda表達式還增強了集合庫 )忘衍。
JUnit 5不再是單個庫逾苫,而是模塊化結構的集合,整個API分成了:自己的模塊枚钓,引擎铅搓,launcher,針對Gradle和Surefire的集成模塊搀捷。
JUnit 5還提供了全新的一套注釋集合星掰,斷言方法從JUnit4的org.junit.Assert包移動到JUnit5的org.junit.gen5.api.Assertions包。
JUnit 5有分組斷言這個新功能(分組斷言允許執(zhí)行一組斷言嫩舟,且會一起報告)氢烘。
JUnit 5基本注解
以下只簡單的介紹幾種常用的基本注解
@Test(表明一個測試方法)
@BeforeAll(執(zhí)行一次,執(zhí)行時機是在所有測試和 @BeforeEach 注解方法之前)
@BeforeEach(在每個測試執(zhí)行之前執(zhí)行)
@AfterEach(在每個測試之后執(zhí)行)
@AfterAll(只執(zhí)行一次家厌,執(zhí)行時機是在所有測試和@AfterEach注解方法之后)
@Disabled(禁止測試類或方法)
@Displayname(測試類或方法的顯示名稱)
JUnit 5斷言
用來對滿足的條件進行驗證播玖,斷言方法都是靜態(tài)方法。
一下介紹幾個常用的基本斷言方法
assertEquals(判斷兩個對象或兩個原始類型是否相等)
assertNotEquals(判斷兩個對象或兩個原始類型是否不相等)
assertSame(判斷兩個對象引用是否指向同一個對象)
assertNotSame(判斷兩個對象引用是否指向不同的對象)
assertTrue(判斷給定的布爾值是否為 true)
assertFalse(判斷給定的布爾值是否為 false)
assertNull (判斷給定的對象引用是否為 null)
assertNotNull(判斷給定的對象引用是否不為 null)
注:以上介紹的這些斷言方法都有多個重載方法饭于。
JUnit 5前置條件
JUnit 5 中的前置條件(assumptions)類似于斷言蜀踏,不同之處在于不滿足的斷言會使得測試方法失敗维蒙,而不滿足的前置條件只會使得測試方法的執(zhí)行終止。前置條件可以看成是測試方法執(zhí)行的前提脓斩,當該前提不滿足時木西,就沒有繼續(xù)執(zhí)行的必要。在如下案例中随静,assumeTrue 和 assumFalse 確保給定的條件為 true 或 false八千,不滿足條件會使得測試執(zhí)行終止。assumingThat 的參數(shù)是表示條件的布爾值和對應的 Executable 接口的實現(xiàn)對象燎猛。只有條件滿足時恋捆,Executable 對象才會被執(zhí)行;當條件不滿足時重绷,測試執(zhí)行并不會終止沸停。
@DisplayName("Assumptions")
public class AssumptionsTest {
private final String environment = "DEV";
@Test
@DisplayName("simple")
public void simpleAssume() {
assumeTrue(Objects.equals(this.environment, "DEV"));
assumeFalse(() -> Objects.equals(this.environment, "PROD"));
}
@Test
@DisplayName("assume then do")
public void assumeThenDo() {
assumingThat(
Objects.equals(this.environment, "DEV"),
() -> System.out.println("In DEV")
);
}
}
擴展機制
JUnit 5 提供了標準的擴展機制來允許開發(fā)人員對 JUnit 5 的功能進行增強。JUnit 5 提供了很多的標準擴展接口昭卓,第三方可以直接實現(xiàn)這些接口來提供自定義的行為愤钾。通過@ExtendWith 注解可以聲明在測試方法和類的執(zhí)行中啟用相應的擴展。
擴展的啟用是繼承的候醒,這既包括測試類本身的層次結構能颁,也包括測試類中的測試方法。也就是說倒淫,測試類會繼承其父類中的擴展伙菊,測試方法會繼承其所在類中的擴展。除此之外敌土,在一個測試上下文中镜硕,每一個擴展只能出現(xiàn)一次。
創(chuàng)建擴展
JUnit 5 中的擴展非常容易創(chuàng)建返干,只是實現(xiàn)了特定接口的 Java 類兴枯。JUnit 5 的擴展都需要實現(xiàn) org.junit.jupiter.api.extension.Extension 接口,不過該接口只是一個標記接口矩欠,并沒有任何需要實現(xiàn)的具體方法念恍。真正起作用的是 Extension 的子接口,作為 JUnit 5 提供的擴展點晚顷。
測試執(zhí)行條件
ContainerExecutionCondition 和 TestExecutionCondition 接口用來配置是否啟用測試類或測試方法。前面提到的@Disabled 注解也是通過這樣的機制來實現(xiàn)的疗疟。ContainerExecutionCondition 接口對應的是測試類该默,而 TestExecutionCondition 接口對應的是測試方法。
ContainerExecutionCondition 接口的 evaluate 方法接受 ContainerExtensionContext 接口作為參數(shù)策彤,并返回 ConditionEvaluationResult 類的對象作為結果栓袖。通過 ContainerExtensionContext 接口可以獲取到當前測試類的上下文信息匣摘,而 ConditionEvaluationResult 類則表示該測試類是否被啟用。
TestExecutionCondition 接口也是包含一個 evaluate 方法裹刮,只不過參數(shù)類型是 TestExtensionContext音榜,其返回結果也是 ConditionEvaluationResult 類的對象。
通過擴展的方式禁用的測試類和方法捧弃,可以通過 JVM 參數(shù) junit.conditions.deactivate 來重新啟用赠叼,只需要把相應的條件類禁用即可。
支持Hamcrest匹配和AssertJ斷言庫
JUnit 5支持Hamcrest匹配和AssertJ斷言庫违霞,可以用它們來代替JUnit 5的方法嘴办。
動態(tài)測試
目前所介紹的 JUnit 5 測試方法的創(chuàng)建都是靜態(tài)的,在編譯時刻就已經(jīng)存在买鸽。JUnit 5 新增了對動態(tài)測試的支持涧郊,可以在運行時動態(tài)創(chuàng)建測試并執(zhí)行。通過動態(tài)測試眼五,可以滿足一些靜態(tài)測試無法解的需求妆艘,也可以完成一些重復性很高的測試。比如看幼,有些測試用例可能依賴運行時的變量批旺,有時候會需要生成上百個不同的測試用例。這些場景都是動態(tài)測試可以發(fā)揮其長處的地方桌吃。動態(tài)測試是通過新的@TestFactory 注解來實現(xiàn)的朱沃。測試類中的方法可以添加@TestFactory 注解的方法來聲明其是創(chuàng)建動態(tài)測試的工廠方法。這樣的工廠方法需要返回 org.junit.jupiter.api.DynamicTest 類的集合茅诱,可以是 Stream逗物、Collection、Iterable 或 Iterator 對象瑟俭。每個表示動態(tài)測試的 DynamicTest 對象由顯示名稱和對應的 Executable 接口的實現(xiàn)對象來組成翎卓。
@TestFactory
public Collection<DynamicTest> simpleDynamicTest() {
return Collections.singleton(dynamicTest("simple dynamic test", () -> assertTrue(2 > 1)));
}
DynamicTest 提供了一個靜態(tài)方法 stream 來根據(jù)輸入生成動態(tài)測試,如清單 14 所示摆寄。
@TestFactory
public Stream<DynamicTest> streamDynamicTest() {
return stream(
Stream.of("Hello", "World").iterator(),
(word) -> String.format("Test - %s", word),
(word) -> assertTrue(word.length() > 4)
);
}
嵌套測試
在嵌套的類上添加 @Nested 注解失暴,類中的所有方法即會被引擎執(zhí)行