前言
上一篇講了 JUnit 5單元測(cè)試(一)—— 基本配置,書(shū)接上文開(kāi)始 JUnit 5單元測(cè)試(二)—— 斷言
一、單元測(cè)試規(guī)范和操作
1.單元測(cè)試的類(lèi)名應(yīng)該起為 xxxxTest.java 表明這個(gè)一個(gè)測(cè)試類(lèi),類(lèi)名應(yīng)該用簡(jiǎn)潔的英文表明測(cè)試內(nèi)容或函數(shù)。
- 例如:為了測(cè)試一個(gè)計(jì)算和的方法,可以取名為 SumTest.java
2.測(cè)試方法上應(yīng)該加上 @Test 注解以表明其是一個(gè)測(cè)試方法。
-
運(yùn)行測(cè)試方法:在 idea 中每個(gè)測(cè)試方法前都有一個(gè)運(yùn)行按鈕,點(diǎn)擊后會(huì)運(yùn)行該測(cè)試方法。
-
運(yùn)行測(cè)試類(lèi):在 idea 中在測(cè)試類(lèi)的類(lèi)名前面有一個(gè)運(yùn)行按鈕,點(diǎn)擊后會(huì)運(yùn)行當(dāng)前測(cè)試類(lèi)中所有的測(cè)試方法。
-你也可以查看單元測(cè)試的覆蓋率
可以看到總的類(lèi)覆蓋率、方法覆蓋率和行覆蓋率
可以雙擊包名點(diǎn)進(jìn)去查看具體不同的包的覆蓋率
3.使用 surefire 運(yùn)行所有單元測(cè)試并生成報(bào)告。
-
你可能會(huì)有很多單元測(cè)試類(lèi)放在了 test/java/ 文件夾下,你可以在 idea 中右側(cè)maven頁(yè)簽中的 Lifecycle 下雙擊 test ,將會(huì)幫你運(yùn)行所有的單元測(cè)試,每個(gè)單元測(cè)試類(lèi)都會(huì)在 target/surefire-reports 下生成 txt 報(bào)告,里面有當(dāng)前單元測(cè)試類(lèi)的執(zhí)行成功、失敗、跳過(guò)、耗時(shí)等信息。
-
生成 txt 報(bào)告后,如果你不想一個(gè)個(gè)去看每個(gè)測(cè)試類(lèi)生成的 txt 報(bào)告,可以在 idea 的 Terminal 命令行窗口輸入
mvn surefire-report:report
命令執(zhí)行,它會(huì)讀取所有 txt 報(bào)告在 target/site/ 下生成 surefire-reports.html 文件,用瀏覽器打開(kāi)該文件你就可以直觀的看到所有單元測(cè)試類(lèi)的所有執(zhí)行情況。 -
二、JUnit5提供的注解
注解 | 描述 |
---|---|
@BeforeEach |
在方法上注解,在每個(gè)測(cè)試方法運(yùn)行之前執(zhí)行。 |
@AfterEach |
在方法上注解,在每個(gè)測(cè)試方法運(yùn)行之后執(zhí)行 |
@BeforeAll |
該注解方法會(huì)在所有測(cè)試方法之前運(yùn)行,該方法必須是靜態(tài)的。 |
@AfterAll |
該注解方法會(huì)在所有測(cè)試方法之后運(yùn)行,該方法必須是靜態(tài)的。 |
@Test |
用于將方法標(biāo)記為測(cè)試方法 |
@DisplayName |
用于為測(cè)試類(lèi)或測(cè)試方法提供說(shuō)明。 |
@Nested |
用于創(chuàng)建嵌套測(cè)試類(lèi)。(注解在測(cè)試類(lèi)的內(nèi)部類(lèi)上) |
@Disable |
用于禁用或忽略測(cè)試類(lèi)或測(cè)試方法 |
@Tag |
用于標(biāo)記測(cè)試方法或測(cè)試類(lèi) |
@TestFactory |
標(biāo)記一種方法是動(dòng)態(tài)測(cè)試的測(cè)試工場(chǎng) |
說(shuō)明:
-
@BeforeAll
:使用 @BeforeAll 注解的方法必須是用 static 修飾的,無(wú)論是運(yùn)行某一個(gè)測(cè)試方法還是運(yùn)行一個(gè)測(cè)試類(lèi),@BeforeAll 注解的方法都會(huì)在所有測(cè)試方法執(zhí)行前運(yùn)行,并只運(yùn)行一次。 -
@BeforeEach
:每個(gè)測(cè)試方法運(yùn)行之前執(zhí)行。如果你運(yùn)行一個(gè)測(cè)試類(lèi),每個(gè)測(cè)試方法執(zhí)行前都會(huì)先執(zhí)行一次@BeforeEach注解的方法。 -
@AfterEach
:每個(gè)測(cè)試方法運(yùn)行之后執(zhí)行。如果你運(yùn)行一個(gè)測(cè)試類(lèi)里,每個(gè)測(cè)試方法執(zhí)行完后都會(huì)執(zhí)行一次@AfterEach注解的方法。 -
@AfterAll
:使用 @AfterAll 注解的方法必須是用 static 修飾的,無(wú)論是運(yùn)行某一個(gè)測(cè)試方法還是運(yùn)行一個(gè)測(cè)試類(lèi),@AfterAll 注解的方法都會(huì)在所有測(cè)試方法執(zhí)行完后運(yùn)行,并只運(yùn)行一次。 -
@Disable
:當(dāng)運(yùn)行一個(gè)測(cè)試類(lèi)時(shí)被 @Disable 注解的測(cè)試方法會(huì)被忽略,不會(huì)被運(yùn)行。
三、斷言
1.什么是斷言
斷言就是專(zhuān)門(mén)用來(lái)驗(yàn)證輸出和期望是否一致的一個(gè)工具。換句話(huà)說(shuō)斷言就是判斷一個(gè)方法所產(chǎn)生的結(jié)果是否符合你期望的那個(gè)結(jié)果。
例如:如果你寫(xiě)個(gè)一個(gè)方法 sum( ) 用來(lái)計(jì)算兩個(gè)數(shù)的和,那現(xiàn)在你想驗(yàn)證下你這個(gè)方法計(jì)算 1+1 是不是 2,你可以使用 assertEquals 斷言方法,就像這樣 assertEquals(2, sum(1,1)) ,如果 你 sum 方法計(jì)算 1+1 后返回的不是 2,那么測(cè)試方法斷言就失敗了這里就會(huì)報(bào)錯(cuò)提示你;如果返回的就是預(yù)期的2,那么就會(huì)繼續(xù)執(zhí)行 assertEquals 斷言后的語(yǔ)句。
2.斷言方法
除了上面提到的 assertEquals 斷言方法,junt5 還提供了許多其他斷言方法。
斷言方法 | 說(shuō)明 |
---|---|
assertEquals(expected, actual, message) | 如果預(yù)期值 expected 不等于實(shí)際返回值 actual ,則斷言失敗。 |
assertNotEquals(expected, actual, message) | 如果預(yù)期值 expected 等于實(shí)際返回值 actual ,則斷言失敗。 |
assertTrue(booleanExpression, message) | 如果 booleanExpression 不是 true ,則斷言失敗。 |
assertFalse(booleanExpression, message) | 如果 booleanExpression 不是 false ,則斷言失敗。 |
assertNull(actual, message) | 如果 actual 不是 null ,則斷言失敗。 |
assertNotNull(actual, message) | 如果 actual 是 null ,則斷言失敗。 |
assertSame(object1, object2, message) | 如果兩個(gè)對(duì)象引用沒(méi)有指向同一個(gè)對(duì)象,則斷言失敗 |
assertNotSame(object1, object2, message) | 如果兩個(gè)對(duì)象引用指向同一個(gè)對(duì)象,則斷言失敗 |
assertArrayEquals(object1, object2, message) | 如果方兩個(gè)數(shù)組不相等,則斷言失敗 |
assertIterableEquals(Iterable1,Iterable2, message) | 如果方兩個(gè)列表集合的元素順序或大小不相等,則斷言失敗 |
assertTimeout(expectedTimeout, executable, message) | 如果執(zhí)行的方法超過(guò)預(yù)期的時(shí)間,則斷言失?。](méi)執(zhí)行完的代碼會(huì)繼續(xù)執(zhí)行) |
assertTimeoutPreemptively(expectedTimeout, executable, message) | 如果執(zhí)行的方法超過(guò)預(yù)期的時(shí)間,則斷言失?。](méi)執(zhí)行完的代碼會(huì)結(jié)束執(zhí)行) |
fail(failmessage) | 拋出異常 |
(1)message :上面這些斷言方法里的 message 參數(shù)是可選的,當(dāng)有 message 參數(shù)時(shí)如果斷言失敗時(shí)就會(huì)輸出 message 內(nèi)容;若沒(méi)有 message 參數(shù),斷言失敗則默認(rèn)提示org.opentest4j.AssertionFailedError,例如:
//如果斷言失敗會(huì)報(bào)錯(cuò)org.opentest4j.AssertionFailedError
assertEquals(3, sum(1,1));
//如果斷言失敗會(huì)報(bào)錯(cuò)org.opentest4j.AssertionFailedError: 斷言失敗啦!sum(1,1)得到的結(jié)果不是預(yù)期的2,請(qǐng)檢查sum方法!
assertEquals(2, sum(1,1),"斷言失敗啦!sum(1,1)得到的結(jié)果不是預(yù)期的2,請(qǐng)檢查sum方法!");
(2)fail 斷言方法:上面的最后一個(gè) fail 斷言方法用來(lái)拋出異常,使測(cè)試方法運(yùn)行到 fail 方法時(shí)立即失敗終止(如果是運(yùn)行的整個(gè)測(cè)試類(lèi),測(cè)試類(lèi)里的其他測(cè)試方法將會(huì)繼續(xù)運(yùn)行,只會(huì)終止當(dāng)前測(cè)試方法)。fail 方法一般用于當(dāng)代碼執(zhí)行到了某個(gè)不應(yīng)該被到達(dá)的分支時(shí)使用 fail 方法終止測(cè)試方法并給出提示信息;或者在catch塊中拋出異常信息。示例:
@Test
public void demo() {
if ("a".equals("b")) {
System.out.println("a等于b");
}else {
fail("a不等于b,拋出錯(cuò)誤");
}
}
@Test
public void divisionCheck() {
try {
int a=2/0;
} catch (Exception e) {
fail(e.getMessage());
}
}
(3)assertIterableEquals
- assertIterableEquals:用于比較兩個(gè)Iterable對(duì)象(如List、Set等)中的元素是否相等(元素在集合對(duì)象中的順序要一致),不需要這兩個(gè)對(duì)象具有相同的類(lèi)型。
List<String> arrList = new ArrayList<>(asList("Java", "Junit", "Test"));
List<String> linList = new LinkedList<>(asList("Java", "Junit", "Test"));
//arrList和linList雖然一個(gè)是ArrayList一個(gè)是LinkedList類(lèi)型,但他們?cè)囟枷嗤詳嘌猿晒?/span>
assertIterableEquals(arrList, linList);
(4)上面所有斷言方法示例:
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("斷言測(cè)試類(lèi)")
public class AssertTest {
@DisplayName("斷言測(cè)試方法")
@Test
public void testAssertions() {
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = null;
String str4 = "abc";
String str5 = "abc";
int val1 = 5;
int val2 = 6;
String[] expectedArray = {"one", "two", "three"};
String[] resultArray = {"one", "two", "three"};
List<String> arrList = new ArrayList<>(asList("Java", "Junit", "Test"));
List<String> linList = new LinkedList<>(asList("Java", "Junit", "Test"));
assertEquals(str1, str2);
assertNotEquals(3, 2, "error");
assertTrue(val1 < val2);
assertFalse(val1 > val2);
assertNotNull(str1);
assertNull(str3);
assertSame(str4, str5, "斷言失敗,str4和str5指向的對(duì)象不一樣");
assertNotSame(str1, str3);
assertArrayEquals(expectedArray, resultArray);
assertIterableEquals(arrList, linList);
assertTimeout(
Duration.ofSeconds(2),
() -> {
Thread.sleep(1000);
}
);
}
}
所有斷言成功,運(yùn)行效果如下:
四、assertThat斷言
雖然上面的一些斷言方法已經(jīng)滿(mǎn)足了日常的一些測(cè)試,但是還不夠豐富和靈活。
例如:如果你一個(gè)字符串是只有等于 “abcdef”,并且長(zhǎng)度是6,以ab開(kāi)始,并且包含 de 才算斷言成功,那你需要寫(xiě)好幾個(gè)斷言語(yǔ)句或者判斷方法,而 assertThat 就可以很方便的做到這一點(diǎn)。
assertThat 斷言是第三方庫(kù) AssertJ-core 所提供的方法,AssertJ-core 提供了一組類(lèi)和實(shí)用方法,使我們能夠輕松地編寫(xiě)流暢而漂亮的斷言。
在 pom.xml 中添加 AssertJ-core 依賴(lài):
<!-- assertj-core用于單元測(cè)試中使用assertThat斷言-->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
assertThat斷言挺簡(jiǎn)單的,下面會(huì)用一些實(shí)例來(lái)快速介紹使用 assertThat 對(duì)常見(jiàn)類(lèi)型的斷言使用。
1. int斷言
@Test
public void intAssertThat() {
int a = 22;
//只有a為大于10小于30并且等于22時(shí),斷言才成功
assertThat(a)
.isGreaterThan(10)
.isLessThan(30)
.isEqualTo(22);
}
2.字符斷言
@Test
public void intAssertThat() {
//只有c不等于a,且在 Unicode 表中,且大于w(即在w之后),且是小寫(xiě)時(shí)斷言才成功
char c = 'x';
assertThat(c)
.isNotEqualTo('a')
.inUnicode()
.isGreaterThanOrEqualTo('w')
.isLowerCase();
}
3.字符串?dāng)嘌?/h3>
@Test
public void charAssertThat() {
//字符串?dāng)嘌?只有str1等于str2,并且str1長(zhǎng)度是11,包含“123”,以“ab”開(kāi)頭,以“fg”結(jié)尾 時(shí)斷言才成功
String str1 = "abcd1234efg";
String str2 = new String("abcd1234efg");
assertThat(str1)
.isEqualTo(str2)
.hasSize(11)
.contains("123")
.startsWith("ab")
.endsWith("fg");
}
4.boolean斷言
@Test
public void boolAssertThat() {
boolean bo1 = true;
boolean bo2 = true;
//只有bo1為true并且等于bo2時(shí)斷言才成功
assertThat(bo1)
.isTrue()
.isEqualTo(bo2);
}
5.List和數(shù)組斷言
@Test
public void charAssertThat() {
//字符串?dāng)嘌?只有str1等于str2,并且str1長(zhǎng)度是11,包含“123”,以“ab”開(kāi)頭,以“fg”結(jié)尾 時(shí)斷言才成功
String str1 = "abcd1234efg";
String str2 = new String("abcd1234efg");
assertThat(str1)
.isEqualTo(str2)
.hasSize(11)
.contains("123")
.startsWith("ab")
.endsWith("fg");
}
@Test
public void boolAssertThat() {
boolean bo1 = true;
boolean bo2 = true;
//只有bo1為true并且等于bo2時(shí)斷言才成功
assertThat(bo1)
.isTrue()
.isEqualTo(bo2);
}
5.1 對(duì) List 和數(shù)組斷言:
@Test
public void listArrayAssertThat1() {
//只有l(wèi)ist1不為空(不為null且size大于0)且包含元素1,且包含元素3和4,且所有元素不為null,且等于list2 時(shí),斷言才成功
List<String> list1 = Arrays.asList("1", "2", "3", "4");
List<String> list2 = Arrays.asList("1", "2", "3", "4");
assertThat(list1)
.isNotEmpty()
.contains("1")
.containsSequence("3","4")
.doesNotContainNull()
.isEqualTo(list2);
//只有array1不為null且包含元素3,且等于array2 ,且數(shù)組長(zhǎng)度是3時(shí),斷言才成功
String[] array1 ={"1", "2", "3"};
String[] array2 ={"1", "2", "3"};
assertThat(array1)
.isNotNull()
.contains("3")
.isEqualTo(array2)
.hasSize(3);
}
5.2 對(duì) List 的每個(gè)元素過(guò)濾斷言:
@Test
public void listArrayAssertThat2() {
List<String> list = Arrays.asList("1-a", "2-b", "3-c", "4-d","5-e ok");
//只有l(wèi)ist中每個(gè)元素都含有"-",并且至少有一個(gè)元素含有"ok"時(shí),斷言才成功
assertThat(list)
.allMatch(v->v.contains("-"))
.anyMatch(v->v.contains("ok"));
}
5.3 對(duì)List的進(jìn)行過(guò)濾得到新的一個(gè)List進(jìn)行斷言:
假設(shè)有Student類(lèi)如下
public class Student {
public String name;
public int id;
public Student(String name, int id) {
this.name = name;
this.id = id;
}
//省略name和id的get/set方法
//...
}
@Test
public void listArrayAssertThat2() {
List<Student> stuList = new ArrayList<>();
stuList.add(new Student("Jerry",1));
stuList.add(new Student("Tom",2));
stuList.add(new Student("Lucy",3));
//過(guò)濾篩選出 stuList 里所有 name 叫 Tom 的,然后斷言其數(shù)量只有一個(gè)
assertThat(stuList)
.filteredOn(v->"Tom".equals(v.getName()))
.hasSize(1);
}
再來(lái)一個(gè)例子:
@Test
public void listFilterAssertThat() {
List<Student> stuList = new ArrayList<>();
Student student1 = new Student("張三",1);
Student student2 = new Student("李四",2);
Student student3 = new Student("王五",3);
stuList.add(student1);
stuList.add(student2);
stuList.add(student3);
List<String> nameList = Arrays.asList("張三","李四","王五");
//extracting函數(shù)調(diào)用 getName 獲取所有學(xué)生的姓名為一個(gè)新的List,然后只有這個(gè)新的List包含元素李四,且這個(gè)新是List等于nameList,斷言才成功
assertThat(stuList)
.extracting(Student::getName)
.contains("李四")
.isEqualTo(nameList);
}
}
6.Map斷言
@Test
public void mapAssertThat() {
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 5);
map.put(2, 7);
map.put(3, 15);
//只有map不為空(不為null且size大于0),且包含key是2,且不包含key是10,且包含value是5,且包含鍵值分別是3和15時(shí),斷言才成功
assertThat(map)
.isNotEmpty()
.containsKey(2)
.doesNotContainKeys(10)
.containsValue(5)
.contains(entry(3, 15));
}
7.對(duì)象斷言
斷言?xún)蓚€(gè)對(duì)象的所有字段的值相等
@Test
public void objectAssertThat() {
//假設(shè)你有Student類(lèi)
Student student1 = new Student("張三",1);
Student student2 = new Student("張三",1);
//只有student1的所有字段的值分別等于student2的字段的值時(shí),斷言才成功
assertThat(student1)
.usingRecursiveComparison()
.isEqualTo(student2);
}
對(duì)對(duì)象的字段進(jìn)行斷言:
@Test
public void objectAssertThat() {
//假設(shè)你有Student類(lèi)
Student student = new Student("tom jeff",4);
//student的name字段的值包含jeff時(shí),斷言才成功
assertThat(student.getName())
.contains("jeff");
//student的id字段的值大于3小于5時(shí),斷言才成功
assertThat(student.getId())
.isLessThan(5)
.isGreaterThan(3);
}
五、參數(shù)化測(cè)試
假如需要判斷一個(gè)數(shù)字是不是奇數(shù),你可能會(huì)寫(xiě)一個(gè)測(cè)試方法然后去斷言判斷,那現(xiàn)在如果你想測(cè)試一批其他數(shù)字呢?
這時(shí)候就可以用參數(shù)化測(cè)試,就相當(dāng)于從那一批數(shù)據(jù)中每次取一個(gè)數(shù)據(jù)傳入測(cè)試方法進(jìn)行測(cè)試。
1.參數(shù)化測(cè)試的規(guī)則
(1) 測(cè)試方法上使用 @ParameterizedTest 注解代替 @Test 注解,以表明其是一個(gè)參數(shù)化測(cè)試方法;
(2) 你可以使用 @ValueSource 或 @EnumSource 或 MethodSource 或 @CsvFileSource ,來(lái)分別從值類(lèi)型、枚舉類(lèi)型、方法類(lèi)型、外部csv文件類(lèi)型來(lái)傳入所有你要測(cè)試的所有數(shù)據(jù)。下面就介紹下這幾種注解的參數(shù)化測(cè)試使用方法。
2.值類(lèi)型
值類(lèi)型是使用 @ValueSource 來(lái)給參數(shù)化測(cè)試方法傳遞一批數(shù)據(jù),@ValueSource中可接收的數(shù)據(jù)類(lèi)型是:
- short (使用 shorts )
- byte (使用 bytes )
- int (使用 ints )
- long (使用 longs )
- float (使用 floats )
- double (使用 doubles )
- char (使用 chars )
- java.lang.String (使用 strings )
- java.lang.Class (使用 classes )
下面使用參數(shù)化測(cè)試來(lái)分別測(cè)試 1, 3, 5, -3, 15, Integer.MAX_VALUE 這幾個(gè)數(shù)是不是奇數(shù):
@ParameterizedTest
@ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE})
void isOddNumbers(int number) {
assertTrue(isOdd(number));
}
public static boolean isOdd(int number) {
return number % 2 != 0;
}
測(cè)試結(jié)果如下:
2.枚舉類(lèi)型
使用@EnumSource可以從枚舉類(lèi)里傳遞數(shù)據(jù)給參數(shù)化測(cè)試方法進(jìn)行測(cè)試
假設(shè)擁有Month枚舉類(lèi)如下:
public enum Month {
January(1), February(2), March(3), April(4), May(5), June(5), July(7), August(8), September(9), October(10), November(11), December(12);
private final int month;
Month(int month){
this.month = month;
}
public int getValue() {
return month;
}
}
單元測(cè)試方法:
@ParameterizedTest
@EnumSource(Month.class) // 從Month枚舉類(lèi)里每次取一個(gè)月份
void getValueForAMonth_IsAlwaysBetweenOneAndTwelve(Month month) {
int monthNumber = month.getValue();
assertTrue(monthNumber >= 1 && monthNumber <= 12);
}
測(cè)試結(jié)果:
如果你不想測(cè)試Month類(lèi)里的所有枚舉。只想測(cè)試Month類(lèi)里的三月和五月,可以使用names來(lái)過(guò)濾出它們進(jìn)行測(cè)試
@ParameterizedTest
@EnumSource(value = Month.class, names = {"March", "May"})
void getValueForAMonth_IsAlwaysBetweenOneAndTwelve(Month month) {
int monthNumber = month.getValue();
assertTrue(monthNumber >= 1 && monthNumber <= 12);
}
3.外部csv文件類(lèi)型
上面的值類(lèi)型和枚舉類(lèi)型每次都只能傳遞一個(gè)值,而使用外部csv文件類(lèi)型可以每次傳遞多個(gè)值。
示例:
在resources資源文件夾下新建students.csv文件,內(nèi)容如下:
id,姓名,分?jǐn)?shù)
1,Tom,80
2,Jerry,90
3,Merry,75
下面的測(cè)試方法將讀取students.csv文件的每一行,每次傳入id,name,score這三個(gè)參數(shù)進(jìn)行測(cè)試。
numLinesToSkip是跳過(guò)students.csv文件第1的標(biāo)題(如果你的csv文件沒(méi)有標(biāo)題可去除numLinesToSkip屬性)
@ParameterizedTest
@CsvFileSource(resources = "/students.csv", numLinesToSkip = 1)
void checkStudent(int id,String name, int score) {
assertThat(id).isLessThan(10); //斷言id是否小于10
assertThat(name).hasSizeGreaterThan(2); //斷言name長(zhǎng)度是否大于2
assertThat(score).isGreaterThan(60); //斷言score是否大于60
}
4.方法類(lèi)型
上面的三種方式參數(shù)來(lái)源都比較簡(jiǎn)單,并且都有局限性。使用它們很難傳遞復(fù)雜的對(duì)象,而使用方法類(lèi)型可以提供更復(fù)雜的參數(shù)。
方法類(lèi)型使用 @MethodSource 注解,其傳遞參數(shù)過(guò)來(lái)的方法必須是 static 修飾的靜態(tài)方法,并且其返回值必須是stream流或數(shù)組(如:Stream, DoubleStream, LongStream, IntStream, Collection, Iterator, Iterable、Object[], String[]等)
示例(1):
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void isBlankOrNullStrings(String input, boolean expected) {
boolean actual = input == null || input.trim().isEmpty();
assertEquals(expected,actual);
}
//返回一組數(shù)據(jù),該組數(shù)據(jù)第一個(gè)參數(shù)是字符串,第二個(gè)參數(shù)是表明第一個(gè)參數(shù)是否為空
private static Stream<Arguments> provideStringsForIsBlank() {
return Stream.of(
Arguments.of(null, true),
Arguments.of("", true),
Arguments.of(" ", true),
Arguments.of("abc", false)
);
}
示例(2):
getStudents方法返回List流(相當(dāng)于返回多個(gè)Student對(duì)象)測(cè)試
@ParameterizedTest
@MethodSource("getStudents")
//getStudents將返回List<Student>流,studentsCheck接收3次流里的數(shù)據(jù)測(cè)試
void studentsCheck(Student student) {
assertThat(student.getName()).hasSizeGreaterThan(2); //斷言該學(xué)生的姓名長(zhǎng)度大于2
assertThat(student.getId()).isLessThan(5); //斷言該學(xué)生的id小于5
}
private static Stream<Student> getStudents() {
List<Student> stuList = new ArrayList<>();
stuList.add(new Student("tom",1));
stuList.add(new Student("jerry",2));
stuList.add(new Student("lory",3));
return stuList.stream();
}
示例(3):
接收方法返回的多個(gè)復(fù)雜參數(shù)測(cè)試
@ParameterizedTest
@MethodSource("getArguments")
//getArguments方法將傳遞兩次數(shù)據(jù)過(guò)來(lái)測(cè)試,一次是(stuList1, intList1, "99"),一次是stuList2, intList2, "100")
void studentsCheck(List<Student> stuList, List<Integer> intList, String score) {
System.out.println(intList);
System.out.println(score);
//斷言stuList中的每個(gè)學(xué)生姓名都包含"_"
assertThat(stuList).allMatch(v -> v.getName().contains("_"));
//斷言stuList中有學(xué)生姓名叫"lory_3"
assertThat(stuList).extracting(v -> v.getName()).contains("lory_3");
//斷言intList中的每個(gè)數(shù)都在0到7之間
assertThat(intList).allMatch(v -> v > 0 && v < 7);
//斷言score字符串長(zhǎng)度大于1
assertThat(score).hasSizeGreaterThan(1);
}
private static Stream<Arguments> getArguments() {
List<Student> stuList1 = new ArrayList<>();
stuList1.add(new Student("tom_1", 1));
stuList1.add(new Student("jerry_2", 2));
stuList1.add(new Student("lory_3", 3));
List<Student> stuList2 = new ArrayList<>();
stuList2.add(new Student("tom_4", 4));
stuList2.add(new Student("jerry_5", 5));
stuList2.add(new Student("lory_3", 3));
List<Integer> intList1 = Arrays.asList(1, 2, 3);
List<Integer> intList2 = Arrays.asList(4, 5, 6);
List<Arguments> arguments = new LinkedList<>();
arguments.add(Arguments.of(stuList1, intList1, "99"));
arguments.add(Arguments.of(stuList2, intList2, "100"));
return arguments.stream();
}
到這里你應(yīng)該能夠很熟練的使用單元測(cè)試和斷言了,上面的斷言示例只是列舉了常用的一些斷言方法,還有文件流斷言、類(lèi)斷言等這里沒(méi)做過(guò)多的解釋?zhuān)渌暾姆椒ê徒忉尶蓞⒖枷旅娴逆溄印?/p>
六、JUnit 5單元測(cè)試(三)—— Mockito 模擬
限于篇幅,單元測(cè)試相關(guān) Mockito 模擬看我下一篇文章:JUnit 5單元測(cè)試(三)—— Mockito 模擬文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-793636.html
參考:
AssertJ - fluent assertions java library
添加鏈接描述
Introduction to AssertJ
usingRecursiveComparison說(shuō)明
JUNIT 5: USING LISTS AS AN ARGUMENT FOR PARAMETERIZED TESTS
Single Assert Call for Multiple Properties in Java Unit Testing文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-793636.html
到了這里,關(guān)于JUnit 5單元測(cè)試(二)—— 斷言的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!