這些方法都有多個重載方法,可以提供額外的消息來作為斷言不滿足時的提示消息,還可以接受 Java 8 中的 Supplier 接口來獲取要判斷的值和顯示的消息。清單 4 中給出了簡單斷言的使用示例。
清單 4. 簡單斷言
@Test
@DisplayName("simple assertion")
public void simple() {
assertEquals(3, 1 + 2, "simple math");
assertNotEquals(3, 1 + 1);
assertNotSame(new Object(), new Object());
Object obj = new Object();
assertSame(obj, obj);
assertFalse(1 > 2);
assertTrue(1 < 2);
assertNull(null);
assertNotNull(new Object());
}
第二類是通過 assertArrayEquals 方法來判斷兩個對象或原始類型的數(shù)組是否相等,如清單 5 所示。
清單 5. assertArrayEquals 方法的示例
@Test
@DisplayName("array assertion")
public void array() {
assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
第三類是通過 assertAll 方法來判斷一組斷言是否滿足。assertAll 方法接受多個 org.junit.jupiter.api.Executable 函數(shù)式接口的實例作為要驗證的斷言,可以通過 lambda 表達式很容易的提供這些斷言,如清單 6 所示。
清單 6. assertAll 方法的示例
@Test
@DisplayName("assert all")
public void all() {
assertAll("Math",
() -> assertEquals(2, 1 + 1),
() -> assertTrue(1 > 0)
);
}
第四類是通過 assertThrows 或 expectThrows 來判斷是否拋出期望的異常類型。兩個方法的參數(shù)都是所期望的異常類型和對應的 Executable 接口的實現(xiàn)對象,區(qū)別在于 expectThrows 方法會返回拋出的異常對象。在清單 7 中,1/0 會拋出 ArithmeticException 異常,assertThrows 用來驗證這一點。
清單 7. assertThrows 和 expectThrows 方法的示例
@Test
@DisplayName("throws exception")
public void exception() {
assertThrows(ArithmeticException.class, () -> System.out.println(1 / 0));
}
第五類是 fail 方法,用來使一個測試方法失敗。清單 8 中的測試會直接失敗。
清單 8. 通過 fail 方法直接使得測試失敗
@Test
@DisplayName("fail")
public void shouldFail() {
fail("This should fail");
}
JUnit 5 前置條件
JUnit 5 中的前置條件(assumptions)類似于斷言,不同之處在于不滿足的斷言會使得測試方法失敗,而不滿足的前置條件只會使得測試方法的執(zhí)行終止。前置條件可以看成是測試方法執(zhí)行的前提,當該前提不滿足時,沒有繼續(xù)執(zhí)行的必要。在清單 9 中,assumeTrue 和 assumFalse 確保給定的條件為 true 或 false,不滿足條件會使得測試執(zhí)行終止。assumingThat 的參數(shù)是表示條件的布爾值和對應的 Executable 接口的實現(xiàn)對象。只有條件滿足時,Executable 對象才會被執(zhí)行;當條件不滿足時,測試執(zhí)行并不會終止。
清單 9. JUnit 5 前置條件
@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 可以通過 Java 中的內部類和@Nested 注解實現(xiàn)嵌套測試,從而可以更好的把相關的測試方法組織在一起。在內部類中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的層次沒有限制。清單 10 中給出了使用嵌套測試的示例,用來測試 HashMap 的功能。
清單 10. 嵌套測試
@DisplayName("Nested tests for HashMap")
public class MapNestedTest {
Map<String, Object> map;
@Nested
@DisplayName("when a new")
class WhenNew {
@BeforeEach
void create() {
map = new HashMap<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(map.isEmpty());
}
@Nested
@DisplayName("after adding a new entry")
class AfterAdd {
String key = "key";
Object value = "value";
@BeforeEach
void add() {
map.put(key, value);
}
@Test
@DisplayName("is not empty")
void isNotEmpty() {
assertFalse(map.isEmpty());
}
@Test
@DisplayName("returns value when getting by key")
void returnValueWhenGettingByKey() {
assertEquals(value, map.get(key));
}
@Nested
@DisplayName("after removing the entry")
class AfterRemove {
@BeforeEach
void remove() {
map.remove(key);
}
@Test
@DisplayName("is empty now")
void isEmpty() {
assertTrue(map.isEmpty());
}
@Test
@DisplayName("returns null when getting by key")
void returnNullForKey() {
assertNull(map.get(key));
}
}
}
}
}
依賴注入
在 JUnit 5 之前,標準的測試類和測試方法是不允許有額外的參數(shù)的。這個限制在 JUnit 5 被取消了。JUnit 5 除了提供內置的標準參數(shù)之外,還可以通過擴展機制來支持額外的參數(shù)。
當參數(shù)的類型是 org.junit.jupiter.api.TestInfo 時,JUnit 5 會在運行測試時提供一個 TestInfo 接口的對象。通過 TestInfo 接口,可以獲取到當前測試的相關信息,包括顯示名稱、標簽、測試類和測試方法,如清單 11 所示。
清單 11. TestInfo 依賴注入
@Test
@DisplayName("test info")
public void testInfo(final TestInfo testInfo) {
System.out.println(testInfo.getDisplayName());
}
當參數(shù)的類型是 org.junit.jupiter.api.TestReporter 時,在運行測試時,通過作為參數(shù)傳入的 TestReporter 接口對象,來輸出額外的鍵值對信息。這些信息可以被測試執(zhí)行的監(jiān)聽器 TestExecutionListener 處理,也可以被輸出到測試結果報告中,如清單 12 所示。
清單 12. TestReporter 依賴注入
@Test
@DisplayName("test reporter")
public void testReporter(final TestReporter testReporter) {
testReporter.publishEntry("name", "Alex");
}
除了 TestInfo 和 TestReporter 之外,也可以通過 JUnit 5 的擴展機制來添加對其他類型參數(shù)的支持。將在下面關于 JUnit 5 擴展機制的一節(jié)中進行介紹。