單元測試JUnit5上手


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 注解,使用如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM