一、 為什么使用JUnit5
- JUnit4被廣泛使用,但是許多場景下使用起來語法較為繁瑣鞭达,JUnit5中支持lambda表達式,語法簡單且代碼不冗余皇忿。
- JUnit5易擴展畴蹭,包容性強,可以接入其他的測試引擎鳍烁。
- 功能更強大提供了新的斷言機制叨襟、參數(shù)化測試、重復性測試等新功能幔荒。
- ps:開發(fā)人員為什么還要測試糊闽,單測寫這么規(guī)范有必要嗎?其實單測是開發(fā)人員必備技能爹梁,只不過很多開發(fā)人員開發(fā)任務太重導致調(diào)試完就不管了右犹,沒有系統(tǒng)化得單元測試,單元測試在CI/CD姚垃、編譯打包念链、回歸測試、系統(tǒng)重構時能發(fā)揮巨大的作用积糯,可以在重構后快速測試新的接口是否與原設計有出入掂墓,改動是否破壞了原有邏輯?
二看成、 JUnit5簡介
如圖君编,JUnit5結構如下:
- JUnit Platform:這是Junit提供的平臺功能模塊,通過它绍昂,其它的測試引擎都可以接入Junit實現(xiàn)接口和執(zhí)行啦粹。
- JUnit JUpiter:這是JUnit5的核心,是一個基于JUnit Platform的引擎實現(xiàn)窘游,它包含許多豐富的新特性來使得自動化測試更加方便和強大。
- JUnit Vintage:這個模塊是兼容JUnit3跳纳、JUnit4版本的測試引擎忍饰,使得舊版本的自動化測試也可以在JUnit5下正常運行。
三寺庄、 依賴引入
我們以SpringBoot2.3.1
為例艾蓝,引入如下依賴力崇,防止使用舊的junit4相關接口我們將其依賴排除。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
四赢织、 常用注解
- @BeforeEach:在每個單元測試方法執(zhí)行前都執(zhí)行一遍
- @BeforeAll:在每個單元測試方法執(zhí)行前執(zhí)行一遍(只執(zhí)行一次)
- @DisplayName("商品入庫測試"):用于指定單元測試的名稱
- @Disabled:當前單元測試置為無效亮靴,即單元測試時跳過該測試
- @RepeatedTest(n):重復性測試,即執(zhí)行n次
- @ParameterizedTest:參數(shù)化測試于置,
- @ValueSource(ints = {1, 2, 3}):參數(shù)化測試提供數(shù)據(jù)
五茧吊、 斷言
JUnit Jupiter提供了強大的斷言方法用以驗證結果,在使用時需要借助java8的新特性lambda表達式八毯,均是來自org.junit.jupiter.api.Assertions
包的static
方法搓侄。
assertTrue與
assertFalse用來判斷條件是否為
true或
false
@Test
@DisplayName("測試斷言equals")
void testEquals() {
assertTrue(3 < 4);
}
assertNull與
assertNotNull用來判斷條件是否為
null`
@Test
@DisplayName("測試斷言NotNull")
void testNotNull() {
assertNotNull(new Object());
}
assertThrows
用來判斷執(zhí)行拋出的異常是否符合預期,并可以使用異常類型接收返回值進行其他操作
@Test
@DisplayName("測試斷言拋異常")
void testThrows() {
ArithmeticException arithExcep = assertThrows(ArithmeticException.class, () -> {
int m = 5/0;
});
assertEquals("/ by zero", arithExcep.getMessage());
}
assertTimeout
用來判斷執(zhí)行過程是否超時
@Test
@DisplayName("測試斷言超時")
void testTimeOut() {
String actualResult = assertTimeout(ofSeconds(2), () -> {
Thread.sleep(1000);
return "a result";
});
System.out.println(actualResult);
}
assertAll
是組合斷言话速,當它內(nèi)部所有斷言正確執(zhí)行完才算通過
@Test
@DisplayName("測試組合斷言")
void testAll() {
assertAll("測試item商品下單",
() -> {
//模擬用戶余額扣減
assertTrue(1 < 2, "余額不足");
},
() -> {
//模擬item數(shù)據(jù)庫扣減庫存
assertTrue(3 < 4);
},
() -> {
//模擬交易流水落庫
assertNotNull(new Object());
}
);
}
五讶踪、 重復性測試
在許多場景中我們需要對同一個接口方法進行重復測試,例如對冪等性接口的測試泊交。
JUnit Jupiter通過使用@RepeatedTest(n)
指定需要重復的次數(shù)
@RepeatedTest(3)
@DisplayName("重復測試")
void repeatedTest() {
System.out.println("調(diào)用");
}
六乳讥、 參數(shù)化測試
參數(shù)化測試可以按照多個參數(shù)分別運行多次單元測試這里有點類似于重復性測試,只不過每次運行傳入的參數(shù)不用廓俭。需要使用到@ParameterizedTest
雏婶,同時也需要@ValueSource
提供一組數(shù)據(jù),它支持八種基本類型以及String
和自定義對象類型白指,使用極其方便留晚。
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
@DisplayName("參數(shù)化測試")
void paramTest(int a) {
assertTrue(a > 0 && a < 4);
}
七、 內(nèi)嵌測試
JUnit5提供了嵌套單元測試的功能告嘲,可以更好展示測試類之間的業(yè)務邏輯關系错维,我們通常是一個業(yè)務對應一個測試類,有業(yè)務關系的類其實可以寫在一起橄唬。這樣有利于進行測試赋焕。而且內(nèi)聯(lián)的寫法可以大大減少不必要的類,精簡項目仰楚,防止類爆炸等一系列問題隆判。
@SpringBootTest
@AutoConfigureMockMvc
@DisplayName("Junit5單元測試")
public class MockTest {
//....
@Nested
@DisplayName("內(nèi)嵌訂單測試")
class OrderTestClas {
@Test
@DisplayName("取消訂單")
void cancelOrder() {
int status = -1;
System.out.println("取消訂單成功,訂單狀態(tài)為:"+status);
}
}
}