JUnit5學習之六:引數化測試(Parameterized Tests)基礎
阿新 • • 發佈:2021-02-27
### 歡迎訪問我的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