1. 程式人生 > >JUnit5學習之六:引數化測試(Parameterized Tests)基礎

JUnit5學習之六:引數化測試(Parameterized Tests)基礎

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ### 關於《JUnit5學習》系列 《JUnit5學習》系列旨在通過實戰提升SpringBoot環境下的單元測試技能,一共八篇文章,連結如下: 1. [基本操作](https://blog.csdn.net/boling_cavalry/article/details/108810587) 2. [Assumptions類](https://blog.csdn.net/boling_cavalry/article/details/108861185) 3. [Assertions類](https://blog.csdn.net/boling_cavalry/article/details/108899437) 4. [按條件執行](https://blog.csdn.net/boling_cavalry/article/details/108909107) 5. [標籤(Tag)和自定義註解](https://blog.csdn.net/boling_cavalry/article/details/108914091) 6. [引數化測試(Parameterized Tests)基礎](https://blog.csdn.net/boling_cavalry/article/details/108930987) 7. [引數化測試(Parameterized Tests)進階](https://blog.csdn.net/boling_cavalry/article/details/108942301) 8. [綜合進階(終篇)](https://blog.csdn.net/boling_cavalry/article/details/108952500) ### 本篇概覽 - 本文是《JUnit5學習》系列的第六篇,一起來實戰強大引數化測試(Parameterized Tests),即多次執行同一個測試方法,每次使用不同的引數; - 由於引數化測試功能強大,內容也比前幾篇的知識點多,為了方便大家閱讀和實踐,這裡分為《基礎》和《進階》兩篇來介紹,本篇以學習引數化測試(Parameterized Tests)的基礎知識為主,包含以下內容: 1. 極速體驗; 2. 版本依賴; 3. ValueSource資料來源 4. null、空字串資料來源 5. 列舉資料來源 6. 方法資料來源 7. Csv格式資料來源 8. Csv檔案資料來源 ### 原始碼下載 1. 如果您不想編碼,可以在GitHub下載所有原始碼,地址和連結資訊如下表所示: | 名稱 | 連結 | 備註| | :-------- | :----| :----| | 專案主頁| https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 | | git倉庫地址(https)| https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 | | git倉庫地址(ssh)| [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 | 2. 這個git專案中有多個資料夾,本章的應用在junitpractice資料夾下,如下圖紅框所示: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070618529-1448207941.jpg) 3. junitpractice是父子結構的工程,本篇的程式碼在parameterized子工程中,如下圖: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070619471-1248132716.jpg) ### 極速體驗 1. 現在,咱們以最少的步驟體驗最簡單的引數化測試; 2. 在父工程junitpractice裡新建名為parameterized的子工程,pom.xml內容如下: ```xml ``` 3. 新建測試類HelloTest.java,在這個位置:junitpractice\parameterized\src\test\java\com\bolingcavalry\parameterized\service\impl,內容如下: ```java package com.bolingcavalry.parameterized.service.impl; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.assertTrue; @SpringBootTest @Slf4j @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class HelloTest { @Order(1) @DisplayName("多個字串型入參") @ParameterizedTest @ValueSource(strings = { "a", "b", "c" }) void stringsTest(String candidate) { log.info("stringsTest [{}]", candidate); assertTrue(null!=candidate); } } ``` 4. 執行該測試類,結果如下圖: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070621202-659628563.jpg) 5. 從上圖可見執行引數化測試需要兩步:首先用@ParameterizedTest取代@Test,表名此方法要執行引數化測試,然後用@ValueSource指定每次測試時的引數來自字串型別的陣列:{ "a", "b", "c" },每個元素執行一次; 6. 至此,咱們已體驗過最簡單的引數化測試,可見就是想辦法使一個測試方法多次執行,每次都用不同的引數,接下來有關引數化測試的更多配置和規則將配合實戰編碼逐個展開,一起來體驗吧; ### 版本要求 - 先看看SpringBoot-2.3.4.RELEASE間接依賴的junit-jupiter-5.6.2版本中,ParameterizedTest的原始碼,如下圖紅框所示,此時的ParameterizedTest還只是體驗版: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070621806-26431377.jpg) - 再看看junit-jupiter-5.7.0版本的ParameterizedTest原始碼,此時已經是穩定版了: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070622151-1356425266.jpg) - 綜上所述,如果要使用引數化測試,最好是將junit-jupiter升級到5.7.0或更高版本,如果您的應用使用了SpringBoot框架,junit-jupiter是被spring-boot-starter-test間接依賴進來的,需要排除這個間接依賴,再手動依賴進來才能確保使用指定版本,在pom.xml中執行如下三步操作: 1. dependencyManagement節點新增junit-bom,並指定版本號: ```xml ``` 2. 排除spring-boot-starter-test和junit-jupiter的間接依賴關係: ```xml ``` 3. 新增junit-jupiter依賴,此時會使用dependencyManagement中指定的版本號: ```xml ``` 4. 如下圖,重新整理可見已經用上了5.7.0版本: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070622803-1728731928.jpg) - 版本問題解決了,接下來正式開始學習Parameterized Tests,先要了解的是有哪些資料來源; ### ValueSource資料來源 1. ValueSource是最簡單常用的資料來源,支援以下型別的陣列: ```java short byte int long float double char boolean java.lang.String java.lang.Class ``` 2. 下面是整形陣列的演示: ```java @Order(2) @DisplayName("多個int型入參") @ParameterizedTest @ValueSource(ints = { 1,2,3 }) void intsTest(int candidate) { log.info("ints [{}]", candidate); assertTrue(candidate<3); } ``` 3. 從上述程式碼可見,入參等於3的時候assertTrue無法通過,測試方法會失敗,來看看實際執行效果,如下圖: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070623641-676928142.jpg) ### null、空字串資料來源 1. 在用字串作為入參時,通常要考慮入參為null的情況,此時ValueSource一般會這樣寫: ```java @ValueSource(strings = { null, "a", "b", "c" }) ``` 2. 此時可以使用@NullSource註解來取代上面的null元素,下面這種寫法和上面的效果一模一樣: ```java @NullSource @ValueSource(strings = { "a", "b", "c" }) ``` 3. 執行結果如下圖紅框,可見null作為入參被執行了一次: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070624192-1626341192.jpg) 4. 與@NullSource代表null入參類似,@EmptySource代表空字串入參,用法和執行結果如下圖所示: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070626699-460352862.jpg) 5. 如果想同時用null和空字串做測試方法的入參,可以使用@NullAndEmptySource,用法和執行結果如下圖所示: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070627865-1166233896.jpg) ### 列舉資料來源(EnumSource) 1. EnumSource可以讓一個列舉類中的全部或者部分值作為測試方法的入參; 2. 建立列舉類Types.java,用於接下來的實戰,如下,很簡單隻有三個值: ```java public enum Types { SMALL, BIG, UNKNOWN } ``` 3. 先嚐試用Types的每個值作為入參執行測試,可見只要新增@EnumSource即可,JUnit根據測試方法的入參型別知道要使用哪個列舉: ```java @Order(6) @DisplayName("多個列舉型入參") @ParameterizedTest @EnumSource void enumSourceTest(Types type) { log.info("enumSourceTest [{}]", type); } ``` 4. 執行結果如下圖所示: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070628368-1660602564.jpg) 5. 如果不想執行列舉的所有值,而只要其中一部分,可以在name屬性中指定: ```java @EnumSource(names={"SMALL", "UNKNOWN"}) ``` 6. 執行結果如下圖所示: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070628962-1719014825.jpg) 7. 也可以指定哪些值不被執行,此時要新增mode屬性並設定為EXCLUDE(mode屬性如果不寫,預設值是INCLUDE,前面的例子中就是預設值): ```java @EnumSource(mode= EnumSource.Mode.EXCLUDE, names={"SMALL", "UNKNOWN"}) ``` 8. 執行結果如下,可見SMALL和UNKNOWN都沒有執行: ![在這裡插入圖片描述](https://img2020.cnblogs.com/other/485422/202102/485422-20210227070629755-1440004514.jpg) ### 方法資料來源(MethodSource) 1. @MethodSource可以指定一個方法名稱,該方法返回的元素集合作為測試方法的入參; 2. 先來定義一個方法,該方法一般是static型別(否則要用@TestInstance修飾),並且返回值是Stream型別: ```java stati