springboot2使用JUnit5单元测试使用大全
目錄
一、JUnit5 的變化
1.介紹
2.使用
二、JUnit5常用注解
1.JUnit5的注解與JUnit4的注解有所變化
2.@DisplayName
?3.@BeforeEach、@AfterEach、@BeforeAll、@AfterAll
4.@Disabled
5.@Timeout
6.@SpringBootTest
7.@RepeatedTest
三、斷言
1.簡介
2.簡單斷言
3.數組斷言
4.組合斷言
5.異常斷言
6.超時斷言
7.快速失敗
四、前置條件(assumptions)
五、嵌套測試
六、參數化測試
七、遷移指南
一、JUnit5 的變化
1.介紹
Spring Boot 2.2.0 版本開始引入 JUnit 5 作為單元測試默認庫
作為最新版本的JUnit框架,JUnit5與之前版本的Junit框架有很大的不同。由三個不同子項目的幾個不同模塊組成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上啟動測試框架的基礎,不僅支持Junit自制的測試引擎,其他測試引擎也都可以接入。
JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的編程模型,是JUnit5新特性的核心。內部 包含了一個測試引擎,用于在Junit Platform上運行。
JUnit Vintage: 由于JUint已經發展多年,為了照顧老的項目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的測試引擎。
注意:
SpringBoot 2.4 以上版本移除了默認對 Vintage 的依賴。如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test)
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test,如果需要繼續兼容junit4需要自行引入vintage
<dependency><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId></exclusion></exclusions> </dependency>?
2.使用
(1)引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope> </dependency>?
(2)使用
Junit類具有Spring的功能,@Autowired、比如 @Transactional 標注測試方法,測試完成后自動回滾
@SpringBootTest class Boot05WebAdminApplicationTests {@Test // @Test標注(注意需要使用junit5版本的注解)void contextLoads() {} }二、JUnit5常用注解
1.JUnit5的注解與JUnit4的注解有所變化
JUnit 5 User Guide
* @Test :表示方法是測試方法。但是與JUnit4的@Test不同,他的職責非常單一不能聲明任何屬性,拓展的測試將會由Jupiter提供額外測試
* @ParameterizedTest :表示方法是參數化測試,下方會有詳細介紹
* @RepeatedTest :表示方法可重復執行,下方會有詳細介紹
* @DisplayName :為測試類或者測試方法設置展示名稱
* @BeforeEach :表示在每個單元測試之前執行
* @AfterEach :表示在每個單元測試之后執行
* @BeforeAll :表示在所有單元測試之前執行
* @AfterAll :表示在所有單元測試之后執行
* @Tag :表示單元測試類別,類似于JUnit4中的@Categories
* @Disabled :表示測試類或測試方法不執行,類似于JUnit4中的@Ignore
* @Timeout :表示測試方法運行如果超過了指定時間將會返回錯誤
* @ExtendWith :為測試類或測試方法提供擴展類引用
2.@DisplayName
@DisplayName("junit5功能測試類") public class Junit5Test {@DisplayName("測試displayname注解")@Testvoid testDisplayName() {System.out.println(1);} }?3.@BeforeEach、@AfterEach、@BeforeAll、@AfterAll
@BeforeEach void testBeforeEach() {System.out.println("測試就要開始了..."); }@AfterEach void testAfterEach() {System.out.println("測試結束了..."); }@BeforeAll // 必須靜態方法 static void testBeforeAll() {System.out.println("所有測試就要開始了..."); }@AfterAll // 必須靜態方法 static void testAfterAll() {System.out.println("所有測試已經結束了..."); }4.@Disabled
執行測試類會執行所有測試方法,但是標注@Disabled的測試方法不會執行。
@Disabled @DisplayName("測試方法2") @Test void test2() {System.out.println(2); }5.@Timeout
/** * 規定方法超時時間。超出時間測試出異常 * * @throws InterruptedException */ @Timeout(value = 500, unit = TimeUnit.MILLISECONDS) @Test void testTimeout() throws InterruptedException {Thread.sleep(600); }6.@SpringBootTest
注釋在類上,可以使用springboot的容器等功能。
7.@RepeatedTest
@RepeatedTest(5) @Test void test3() {System.out.println(5); }三、斷言
1.簡介
斷言(assertions)是測試方法中的核心部分,用來對測試需要滿足的條件進行驗證。這些斷言方法都是 org.junit.jupiter.api.Assertions 的靜態方法。JUnit 5 內置的斷言可以分成如下幾個類別:
檢查業務邏輯返回的數據是否合理。
所有的測試運行結束以后,會有一個詳細的測試報告。
2.簡單斷言
用來對單個值進行簡單的驗證。如:
| 方法 | 說明 |
| assertEquals | 判斷兩個對象或兩個原始類型是否相等 |
| assertNotEquals | 判斷兩個對象或兩個原始類型是否不相等 |
| assertSame | 判斷兩個對象引用是否指向同一個對象 |
| assertNotSame | 判斷兩個對象引用是否指向不同的對象 |
| assertTrue | 判斷給定的布爾值是否為 true |
| assertFalse | 判斷給定的布爾值是否為 false |
| assertNull | 判斷給定的對象引用是否為 null |
| assertNotNull | 判斷給定的對象引用是否不為 null |
3.數組斷言
通過 assertArrayEquals 方法來判斷兩個對象或原始類型的數組是否相等
@Test @DisplayName("array assertion") void array() {assertArrayEquals(new int[]{1, 2}, new int[]{1, 2}, "數組內容不相等"); }4.組合斷言
assertAll 方法接受多個 org.junit.jupiter.api.Executable 函數式接口的實例作為要驗證的斷言,可以通過 lambda 表達式很容易的提供這些斷言
@Test @DisplayName("組合斷言") void all() {/*** 所有斷言全部需要成功*/assertAll("test",() -> assertTrue(true && true, "結果不為true"),() -> assertEquals(1, 2, "結果不是1"));System.out.println("====="); }5.異常斷言
在JUnit4時期,想要測試方法的異常情況時,需要用@Rule注解的ExpectedException變量還是比較麻煩的。而JUnit5提供了一種新的斷言方式Assertions.assertThrows() ,配合函數式編程就可以進行使用。
@DisplayName("異常斷言") @Test void testException() {//斷定業務邏輯一定出現異常assertThrows(ArithmeticException.class, () -> {int i = 10 / 2;}, "業務邏輯居然正常運行?"); }6.超時斷言
Junit5還提供了Assertions.assertTimeout() 為測試方法設置了超時時間
@Test @DisplayName("超時測試") public void timeoutTest() {//如果測試方法時間超過1s將會異常Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500)); }7.快速失敗
通過 fail 方法直接使得測試失敗
@DisplayName("快速失敗") @Test void testFail(){//xxxxxif(2 == 2){fail("測試失敗");} }四、前置條件(assumptions)
?? ?JUnit 5 中的前置條件(assumptions【假設】)類似于斷言,不同之處在于不滿足的斷言會使得測試方法失敗,而不滿足的前置條件只會使得測試方法的執行終止。前置條件可以看成是測試方法執行的前提,當該前提不滿足時,就沒有繼續執行的必要。
?? ?assumeTrue 和 assumFalse 確保給定的條件為 true 或 false,不滿足條件會使得測試執行終止。assumingThat 的參數是表示條件的布爾值和對應的 Executable 接口的實現對象。只有條件滿足時,Executable 對象才會被執行;當條件不滿足時,測試執行并不會終止。
/** * 測試前置條件 */ @DisplayName("測試前置條件") @Test void testassumptions(){Assumptions.assumeTrue(false,"結果不是true");System.out.println("111111"); } @DisplayName("前置條件") 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 注解實現嵌套測試,從而可以更好的把相關的測試方法組織在一起。在內部類中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的層次沒有限制。
@DisplayName("A stack") class TestingAStackDemo {Stack<Object> stack;@Test@DisplayName("is instantiated with new Stack()")void isInstantiatedWithNew() {new Stack<>();//嵌套測試情況下,外層的Test不能驅動內層的Before(After)Each/All之類的方法提前/之后運行assertNull(stack);}@Nested // 代表是嵌套測試@DisplayName("when new")class WhenNew {@BeforeEach // 所有測試之前執行,嵌套類中不會在外面執行void createNewStack() {stack = new Stack<>();}@Test@DisplayName("is empty")void isEmpty() {assertTrue(stack.isEmpty());}@Test@DisplayName("throws EmptyStackException when popped")void throwsExceptionWhenPopped() {assertThrows(EmptyStackException.class, stack::pop);}@Test@DisplayName("throws EmptyStackException when peeked")void throwsExceptionWhenPeeked() {assertThrows(EmptyStackException.class, stack::peek);}@Nested@DisplayName("after pushing an element")class AfterPushing {String anElement = "an element";@BeforeEachvoid pushAnElement() {stack.push(anElement);}/*** 內層的Test可以驅動外層的Before(After)Each/All之類的方法提前/之后運行*/@Test@DisplayName("it is no longer empty")void isNotEmpty() {assertFalse(stack.isEmpty());}@Test@DisplayName("returns the element when popped and is empty")void returnElementWhenPopped() {assertEquals(anElement, stack.pop());assertTrue(stack.isEmpty());}@Test@DisplayName("returns the element when peeked but remains not empty")void returnElementWhenPeeked() {assertEquals(anElement, stack.peek());assertFalse(stack.isEmpty());}}} }六、參數化測試
參數化測試是JUnit5很重要的一個新特性,它使得用不同的參數多次運行測試成為了可能,也為我們的單元測試帶來許多便利。
利用@ValueSource等注解,指定入參,我們將可以使用不同的參數進行多次單元測試,而不需要每新增一個參數就新增一個單元測試,省去了很多冗余代碼。
@ValueSource: 為參數化測試指定入參來源,支持八大基礎類以及String類型,Class類型
@NullSource: 表示為參數化測試提供一個null的入參
@EnumSource: 表示為參數化測試提供一個枚舉入參
@CsvFileSource:表示讀取指定CSV文件內容作為參數化測試入參
@MethodSource:表示讀取指定方法的返回值作為參數化測試入參(注意方法返回需要是一個流)
當然如果參數化測試僅僅只能做到指定普通的入參還達不到讓我覺得驚艷的地步。讓我真正感到他的強大之處的地方在于他可以支持外部的各類入參。如:CSV,YML,JSON 文件甚至方法的返回值也可以作為入參。只需要去實現ArgumentsProvider接口,任何外部文件都可以作為它的入參。
@ParameterizedTest @DisplayName("參數化測試") @ValueSource(ints = {1,2,3,4,5}) void testParameterized(int i){System.out.println(i); }@ParameterizedTest @DisplayName("參數化測試") @MethodSource("stringProvider") void testParameterized2(String i){System.out.println(i); }static Stream<String> stringProvider() {return Stream.of("apple", "banana","atguigu"); }七、遷移指南
在進行遷移的時候需要注意如下的變化:
* 注解在 org.junit.jupiter.api 包中,斷言在 org.junit.jupiter.api.Assertions 類中,前置條件在 org.junit.jupiter.api.Assumptions 類中。
* 把@Before 和@After 替換成@BeforeEach 和@AfterEach。
* 把@BeforeClass 和@AfterClass 替換成@BeforeAll 和@AfterAll。
* 把@Ignore 替換成@Disabled。
* 把@Category 替換成@Tag。
* 把@RunWith、@Rule 和@ClassRule 替換成@ExtendWith。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的springboot2使用JUnit5单元测试使用大全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot使用原生servle
- 下一篇: springboot根据环境装配配置文件