1. JUnit5的架構
JUnit 5 與以前版本的 JUnit 不同,拆分成由三個不同子項目的幾個不同模塊組成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
- JUnit Platform: 用於JVM上啟動測試框架的基礎服務,提供命令行,IDE和構建工具等方式執行測試的支持。
- JUnit Jupiter:包含 JUnit 5 新的編程模型和擴展模型,主要就是用於編寫測試代碼和擴展代碼。
- JUnit Vintage:用於在JUnit 5 中兼容運行 JUnit3.x 和 JUnit4.x 的測試用例。

2. JUnit Jupiter API 的使用
該API的基本特性 - 注解、斷言等在平時的單元測試是常用的。與JUnit4相比,部分注解的名稱有改變。
2.1 JUnit Jupiter注解

示例代碼如下:
import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.assertEquals; @Slf4j @SpringBootTest class Junit5demoApplicationTests { @Test void contextLoads() { log.info("default contextLoads running"); } @BeforeAll public static void init() { log.info("Before All, only run once on the start "); } @AfterAll public static void done() { log.info("After All, only run once on the end "); } @BeforeEach public void setUp() throws Exception { log.info("Before Each, run once on the every start "); } @AfterEach public void tearDown() throws Exception { log.info("After Each, run once on the every end "); } @Test @DisplayName("Dummy test") void aTest() { log.info("As written, this test will always pass!"); assertEquals(4, (2 + 2)); } @Test @Disabled @DisplayName("A disabled test") void testNotRun() { log.info("This test will not run (it is disabled, silly)."); } }
執行結果:

主要注解解釋:
- @RunWith 連同它的參數 JUnitPlatform.class (一個基於 JUnit 4 且理解 JUnit Platform 的 Runner )讓您可以在 IDE 內運行 JUnit Jupiter 單元測試。
- @DisplayName 告訴 JUnit 在報告測試結果時顯示 String“Testing using JUnit 5”,而不是測試類的名稱。
- @BeforeAll 告訴 JUnit 在運行這個類中的所有 @Test 方法 之前 運行 init()方法 一次 。
- @AfterAll 告訴 JUnit 在運行這個類中的所有 @Test 方法 之后 運行 done()方法 一次 。
- @BeforeEach 告訴 JUnit 在此類中的 每個@Test 方法 之前 運行 setUp() 方法。
- @AfterEach 告訴 JUnit 在此類中的 每個@Test 方法 之后 運行 tearDown()方法。
- @Test 告訴 JUnit, aTest() 方法是一個 JUnit Jupiter 測試方法。
- @Disabled 告訴 JUnit 不運行此 @Test 方法,因為它已被禁用。
2.2 JUnit Jupiter斷言
斷言 (assertion) 是 org.junit.jupiter.api.Assertions 類上的眾多靜態方法之一。斷言用於測試一個條件,該條件必須計算為 true ,測試才能繼續執行。
如果斷言失敗,測試會在斷言所在的代碼行上停止,並生成斷言失敗報告。如果斷言成功,測試會繼續執行下一行代碼。

使用如下:

如果不正確,會打印如下信息:

通過上面發現一個問題,一些斷言順序執行,如果中途出現一個斷言失敗,那么接下去的斷言就會中止,所以引入另一個斷言 assetAll() 來保證所有斷言能夠順利執行。使用如下:

Junit5中新添加了對方法拋出異常的斷言Assertions類中的assertThrows()和assertDoesNotThrow(),使用此方法可以對被測試方法拋出的異常進行斷言測試,使用如下:

- assertThrows()主要對被測試方法的拋出異常進行測試,測試所拋出的異常是否滿足預期。
- assertDoesNotThrow()主要用來判定被測試方法是否拋出了異常,如果拋出異常則斷言失敗,無異常拋出則斷言成功。
3. 運行時測試
在實際項目開發中,有些變量需要結合上下文來測試,SpringBoot為我們提供了很好的集成 - @SpringBootTest,可以通過其實現Bean注入的功能。下面簡單介紹下項目單元測試時用到的幾個注解。
3.1 @SpringBootTest + @Autowired
這兩個注解結合可以實現Bean注入,實現程序中的方法調用。

3.2 @SpringBootTest + @MockBean
如果測試時不想執行實際方法,例如上面例子,執行 mathService.add() 時會操作數據庫,但我們不想讓他執行,只需要其返回結果即可,此時可以在Bean上使用 @MockBean 注解,使用該注解之后,類中方法返回類型為數字的會返回默認值0,返回類型為字符的會返回null,如果不想使用默認值,也可以自定義返回值。

3.3 @SpringBootTest + @SpyBean
觀察3.2 的執行可以發現@MockBean 注解的一個問題:當使用該注解時,整個類中的方法都會返回Mock,如果我們只想讓配置了mock規則的方法返回Mock值,可以使用 @SpyBean 注解,使用如下:

