JUnit5 單元測試框架使用教程
一、Junit5 是什么?
??Junit5是一個用于在Java平臺上進行單元測試的框架。JUnit 5 框架主要由三部分組成:JUnit Platform、JUnit Jupiter 和 JUnit Vintage。
- JUnit Platform:定義了測試引擎的 API,是 JVM 上用于啟動測試框架的基礎服務,支持通過 IDE、構建工具、命令行等方式運行單元測試。
- JUnit Jupiter:包含 JUnit 5 新的編程模型和擴展模型,主要用于編寫和擴展測試代碼。
- JUnit Vintage:兼容運行 JUnit 3 和 JUnit4 編寫的測試用例。
二、Junit5 的注解
(一)導入依賴
??導入五個依賴:
<!-- junit-jupiter-api 里有 @BeforeAll……等注解 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
</dependency>
<!-- junit-jupiter-params 里有 @ValueSource……等注解 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.10.0</version>
</dependency>
<!-- 用于運行 識別上述注解 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<!-- 測試套件 -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-api</artifactId>
<version>1.10.0</version>
</dependency>
<!-- 運行測試套件的測試引擎-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.10.0</version>
<scope>test</scope>
</dependency>
(二)常用的注解
如果你的IDEA在使用JUnit注解的時候發(fā)生如下情況:依賴已經導入且加載完成,但是IDEA沒能識別出來,如圖:
有的注解也在params包中。
(我真的不理解為啥)
有一種解決辦法:
點擊后,選擇相應的版本,我這里是5.10.0,點了之后IDEA就能識別出來了。
現在我也找了很多測試的朋友,做了一個分享技術的交流群,共享了很多我們收集的技術文檔和視頻教程。
如果你不想再體驗自學時找不到資源,沒人解答問題,堅持幾天便放棄的感受
可以加入我們一起交流。而且還有很多在自動化,性能,安全,測試開發(fā)等等方面有一定建樹的技術大牛
分享他們的經驗,還會分享很多直播講座和技術沙龍
可以免費學習!劃重點!開源的?。?!
qq群號:110685036
1.@Test
public class JUnitTest {
@Test
void test0(){
System.out.println("測試用例1");
}
@Test
void test1(){
System.out.println("測試用例2");
}
@Test
void test2(){
System.out.println("測試用例3");
}
}
結果:
2.@BeforeAll、@AfterAll
-
@BeforeAll
:表示被注解的方法應該在當前類的所有@Test,@RepeatedTest,@ParameterizedTest和@TestFactory方法之前執(zhí)行; -
@AfterAll
:表示被注解的方法應該在當前類的所有@Test,@RepeatedTest,@ParameterizedTest和@TestFactory方法之后執(zhí)行;
使用@BeforeAll
和@AfterAll
注解的方法要加上static
。
public class JUnitTest {
@BeforeAll
static void beforeAll(){
//可以用于創(chuàng)建一些資源
System.out.println("我是BeforeAll,我最開始執(zhí)行。");
}
@AfterAll
static void afterAll(){
//可以用于釋放資源
System.out.println("我是AfterAll,我最后執(zhí)行。");
}
@Test
void test0(){
System.out.println("測試用例1");
}
@Test
void test1(){
System.out.println("測試用例2");
}
@Test
void test2(){
System.out.println("測試用例3");
}
}
3.@BeforeEach、@AfterEach
-
@BeforeEach
:表示被注解的方法應在當前類的每個@Test,@RepeatedTest,@ParameterizedTest或@TestFactory方法之前執(zhí)行; -
@AfterEach
:表示被注解的方法應在當前類的每個@Test,@RepeatedTest,@ParameterizedTest或@TestFactory方法之后執(zhí)行;
public class JUnitTest {
@BeforeAll
static void beforeAll(){
System.out.println("我是BeforeAll,我最開始執(zhí)行。");
}
@AfterAll
static void afterAll(){
System.out.println("我是AfterAll,我最后執(zhí)行。");
}
@BeforeEach
void beforeEach(){
System.out.println("我是BeforeEach,我在每個 @Test 前執(zhí)行。");
}
@AfterEach
void afterEach(){
System.out.println("我是AfterEach,我在每個 @Test 后執(zhí)行。");
}
@Test
void test0(){
System.out.println("測試用例1");
}
@Test
void test1(){
System.out.println("測試用例2");
}
@Test
void test2(){
System.out.println("測試用例3");
}
}
結果:
4.@Disabled
??@Disabled用于禁用測試類或測試方法,添加該注解的方法不會被測試。
public class JUnitTest {
@BeforeAll
static void beforeAll(){
System.out.println("我是BeforeAll,我最開始執(zhí)行。");
}
@AfterAll
static void afterAll(){
System.out.println("我是AfterAll,我最后執(zhí)行。");
}
@BeforeEach
void beforeEach(){
System.out.println("我是BeforeEach,我在每個 @Test 前執(zhí)行。");
}
@AfterEach
void afterEach(){
System.out.println("我是AfterEach,我在每個 @Test 后執(zhí)行。");
}
@Test
@Disabled //忽略測試用例1
void test0(){
System.out.println("測試用例1");
}
@Test
void test1(){
System.out.println("測試用例2");
}
@Test
void test2(){
System.out.println("測試用例3");
}
}
結果:
(三)參數化測試
1.@ParameterizedTest + @ValueSource
??@ParameterizedTest
的作用就是可以用不同的參數多次運行測試。但是必須聲調用提供參數的來源(source)。
??@ValueSource
它可以讓你指定一個原生類型(String,int,long或double)的數組,并且只能為每次調用提供一個參數。
public class JUnitTest {
@BeforeAll
static void beforeAll(){
System.out.println("我是BeforeAll,我最開始執(zhí)行。");
}
@AfterAll
static void afterAll(){
System.out.println("我是AfterAll,我最后執(zhí)行。");
}
@BeforeEach
void beforeEach(){
System.out.println("我是BeforeEach,我在每個 Test 前執(zhí)行。");
}
@AfterEach
void afterEach(){
System.out.println("我是AfterEach,我在每個 Test 后執(zhí)行。");
}
@Test
void test0(){
System.out.println("測試用例1");
}
@Test
void test1(){
System.out.println("測試用例2");
}
@Test
void test2(){
System.out.println("測試用例3");
}
@ParameterizedTest
@ValueSource(strings = {"小明","小紅","小蘭"})
void paramTest(String name){
System.out.println(name);
}
}
結果:
2.@ParameterizedTest + @CsvSource
??@CsvSource
允許將參數列表表示為以逗號分隔的值(例如,字符串文字)。
public class JUnitTest {
@ParameterizedTest
@CsvSource({"小明, 1","小紅,2","小蘭,3"})
void csvSource(String name,int id){
System.out.println(name + ":" + id);
}
}
結果:
@CsvSource
使用'
作為轉義字符。
示例輸入 | 結果字符列表 |
---|---|
@CsvSource({ "foo, bar" }) |
"foo" , "bar"
|
@CsvSource({ "foo, 'baz, qux'" }) |
"foo" , "baz, qux"
|
@CsvSource({ "foo, ''" }) |
"foo" , ""
|
@CsvSource({ "foo, " }) |
"foo" , null |
3.@ParameterizedTest + @CsvFileSource
??@CsvFileSource
讓你使用classpath中的CSV文件。CSV文件中的每一行都會導致參數化測試的一次調用。
在resources
目錄下創(chuàng)建csv
文件:
test.csv:
小明, 1
小紅, 2
"小明, 小紅", 3
public class JUnitTest {
@ParameterizedTest
@CsvFileSource(resources = "/test.csv")
void csvFile(String name,int id){
System.out.println(name + ": " + id);
}
}
結果:
與@CsvSource
中使用的語法相反,@CsvFileSource
使用雙引號"
作為轉義字符。通過上面的代碼就可以看出來。一個空的轉義值""
會產生一個空字符串, 一個完全為空的值被解釋為null引用。
4.@ParameterizedTest + @MethodSource
??@MethodSource
允許引用一個或多個測試類的工廠方法。
public class JUnitTest {
@ParameterizedTest
@MethodSource("stringProvider") //指定方法
void methodSource(int age,String name){
System.out.println(age + ": " + name);
}
static Stream<Arguments> stringProvider() {
return Stream.of(
Arguments.arguments(12,"李四"),
Arguments.arguments(18,"王五"),
Arguments.arguments(20,"小紅")
);
}
}
??@MethodSource
注解表示這個方法的參數來源于一個名為stringProvider
的靜態(tài)方法。stringProvider
方法返回一個Stream<Arguments>
類型的對象,其中每個Arguments
對象包含了一組用于測試的參數。
(四)測試方法的執(zhí)行順序
1.@TestMethodOrder + @Order
??在 JUnit5 中,測試方法執(zhí)行的順序是不確定的或者是根據方法首字母來排序的。
public class JUnitTest2 {
@Test
void C(){
System.out.println("A");
}
@Test
void B(){
System.out.println("B");
}
@Test
void A(){
System.out.println("C");
}
}
結果:
??讓執(zhí)行順序為 C、B、A:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitTest2 {
int a = 0;
@Test
@Order(1)
void C(){
a++;
System.out.println(a);
System.out.println("C");
}
@Test
@Order(2)
void B(){
a++;
System.out.println(a);
System.out.println("B");
}
@Test
@Order(3)
void A(){
a++;
System.out.println(a);
System.out.println("A");
}
}
??首先在類上添加@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
,然后再為每個方法上添加@Order()
注解,值越小越優(yōu)先被執(zhí)行。
(五)測試實例的生命周期
1.@TestInstance
??我添加一個成員變量,每次執(zhí)行測試方法的時候都++
一次。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
public class JUnitTest2 {
int a = 0;
@Test
@Order(1)
void A(){
a++;
System.out.println("A方法:" + a);
System.out.println("A");
}
@Test
@Order(2)
void B(){
a++;
System.out.println("B方法:" + a);
System.out.println("B");
}
@Test
@Order(3)
void C(){
a++;
System.out.println("C方法:" + a);
System.out.println("C");
}
}
結果:
??為了允許隔離執(zhí)行單個的測試方法,JUnit在執(zhí)行每個測試方法之前會創(chuàng)建每個測試類的新實例。如果想改變策略,就要用@TestInstance
,在類上添加@TestInstance(TestInstance.Lifecycle.PER_CLASS)
。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class JUnitTest2 {
int a = 0;
@Test
@Order(1)
void A(){
a++;
System.out.println("A方法:" + a);
System.out.println("A");
}
@Test
@Order(2)
void B(){
a++;
System.out.println("B方法:" + a);
System.out.println("B");
}
@Test
@Order(3)
void C(){
a++;
System.out.println("C方法:" + a);
System.out.println("C");
}
}
結果:
Lifecycle.PER_CLASS
表示只創(chuàng)建一個實例。不添加注解的時候,默認是Lifecycle.PER_METHOD
。
??當使用這種模式時,每個測試類將創(chuàng)建一個新的測試實例。因此,如果測試方法依賴于存儲在實例變量中的狀態(tài),則可能需要在@BeforeEach
或@AfterEach
方法中重置該狀態(tài)(重置變量的值)。
(六)斷言 Assertions
斷言方法 | 描述 |
---|---|
assertEquals(expected, actual) | 檢查兩個值是否相等,如果不相等則拋出AssertionError |
assertNotEquals(expected, actual) | 檢查兩個值是否不相等,如果相等則拋出AssertionError |
assertTrue(condition) | 檢查一個條件是否為真,如果為假則拋出AssertionError |
assertFalse(condition) | 檢查一個條件是否為假,如果為真則拋出AssertionError |
assertNull(object) | 檢查一個對象是否為null,如果不為null則拋出AssertionError |
assertNotNull(object) | 檢查一個對象是否不為null,如果為null則拋出AssertionError |
assertSame(expected, actual) | 檢查兩個對象是否是同一個實例,如果不是則拋出AssertionError |
assertNotSame(expected, actual) | 檢查兩個對象是否不是同一個實例,如果是則拋出AssertionError |
assertArrayEquals(expected, actual) | 檢查兩個數組是否相等,如果不相等則拋出AssertionError |
assertTimeout(duration, executable) | 檢查一個可執(zhí)行的代碼塊是否在指定的時間內完成,如果超時則拋出AssertionError |
public class JUnitTest3 {
@Test
void assertEqualsDemo(){
int num = 10;
Assertions.assertEquals(1,num,"不符合預期");
}
@Test
void assertTrueDemo(){
int num = 10;
Assertions.assertTrue(num > 10,"不符合預期");
}
@Test
void assertTimeoutDemo(){
int num = 10;
Assertions.assertTimeout(Duration.ofSeconds(3), new Executable() {
@Override
public void execute() throws Throwable {
//代碼塊
Thread.sleep(4000);
}
});
}
}
結果:
(七)測試套件
??測試套件是一組相關的測試,可以一起運行,以便更方便地組織和管理測試。使用套件要引入兩個依賴:junit-platform-suite-api
、junit-platform-suite-engine
,具體的在文章開頭。
??套件其實很好理解,就是使幾個類同時進行測試。
1.@SelectClasses
@Suite
@SelectClasses(value = {JUnitTest.class,JUnitTest2.class})
public class RunSuite {
}
@Suite
的作用是將一個類標記為JUnit平臺上的測試套件。
@SelectClasses
指定在JUnit平臺上運行測試套件時要選擇的類。
運行結果:
2.@SelectPackages
??可以選擇類,那么也可以包。
@Suite
@SelectPackages(value = {"package1"})
//可以選擇多個包:@SelectPackages(value = {"package1","package2","package3"……})
public class RunSuite {
}
結果:
為什么只執(zhí)行了JUnitTest
這一個類?我的JUnitTest2
呢?我們來看看它:
IDEA提示我們它的命名不符合規(guī)則,那這個規(guī)則是什么意思呢?
3.測試類命名規(guī)則
- [A-Z[A-Za-z\d]*Test(s|Case)?:表示以大寫字母開頭,后面跟任意個字母或數字,最后以Test, Tests, TestCase結尾的字符串,例如MyTest, MyTests, MyTestCase等。
- Test[A-Z[A-Za-z\d]*:表示以Test開頭,后面跟一個大寫字母,再后面跟任意個字母或數字的字符串,例如TestMyClass, TestMyMethod等。
- IT(.*):表示以IT開頭,后面跟任意個任意字符的字符串,例如ITMyClass, ITMyMethod等。
- (.*)IT(Case)?:表示以任意個任意字符開頭,后面跟IT或者ITCase的字符串,例如MyClassIT, MyMethodITCase等。
其實就是我們的類命名不規(guī)范導致框架識別不出來。改類名后:
最后感謝每一個認真閱讀我文章的人,看著粉絲一路的上漲和關注,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走!
軟件測試面試文檔
我們學習必然是為了找到高薪的工作,下面這些面試題是來自阿里、騰訊、字節(jié)等一線互聯網大廠最新的面試資料,并且有字節(jié)大佬給出了權威的解答,刷完這一套面試資料相信大家都能找到滿意的工作。
?
文章來源:http://www.zghlxwxcb.cn/news/detail-846642.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-846642.html
到了這里,關于【單元測試】如何使用 JUnit5 框架?的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!