SpringBoot實現(xiàn)單元測試示例詳解
一、常用注解
官方文檔:Junit5官網(wǎng)指導
- @Test :表示此方法是測試方法。但是與JUnit4的@Test不同,他的職責非常單一,不能聲明任何屬性,拓展的測試將會由Jupiter提供額外測試
- @ParameterizedTest:參數(shù)化測試使用注解
- @RepeatedTest :表示測試方法可重復執(zhí)行,value表示重復執(zhí)行次數(shù)
- @DisplayName :為測試類或者測試方法設置展示名稱
- @BeforeEach :表示在每個單元測試之前執(zhí)行該方法
- @AfterEach :表示在每個單元測試之后執(zhí)行該方法
- @BeforeAll :表示在所有開始單元測試之前執(zhí)行,此方法必須是靜態(tài)方法
- @AfterAll :表示在所有單元測試完成之后執(zhí)行,此方法必須是靜態(tài)方法
- @Tag :表示單元測試類別,類似于JUnit4中的@Categories
- @Disabled :表示測試類或測試方法不執(zhí)行,類似于JUnit4中的@Ignore
- @Timeout :表示測試方法運行如果超過了指定時間將會返回錯誤
- @SpringBootTest:如果測試類想要使用Spring Boot的自動注入功能,例如@Autowired注解等,就需要在測試類上加上此注解
- @ExtendWith :為測試類或測試方法提供擴展類引用,類似于@RunWith,@RunWith(JUnit4.class) 就是指用JUnit4來運行,@RunWith(SpringJUnit4ClassRunner.class),讓測試運行于Spring測試環(huán)境
package com.decade; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import java.util.concurrent.TimeUnit; @DisplayName("測試類的名稱為MyTest") @SpringBootTest public class MyTest { @Autowired private JdbcTemplate jdbcTemplate; @DisplayName("測試方法名稱為test") @RepeatedTest(value = 3) public void test() { System.out.println("測試方法,打印JdbcTemplate類" + jdbcTemplate); } @Test @Timeout(value = 500, unit = TimeUnit.MILLISECONDS) public void testTimeOut() throws InterruptedException { Thread.sleep(600); } @BeforeEach public void beforeEach() { System.out.println("每個方法前執(zhí)行"); } @AfterEach public void afterEach() { System.out.println("每個方法后執(zhí)行"); } @BeforeAll static void beforeAll() { System.out.println("所有方法前執(zhí)行"); } @AfterAll static void afterAll() { System.out.println("所有方法后執(zhí)行"); } @Disabled @Test public void disableTest() { System.out.println("此內(nèi)容不輸出"); } }
二、斷言機制
斷言是測試方法中的核心部分,它用于檢查業(yè)務邏輯返回的數(shù)據(jù)是否合理,不滿足的斷言會使得測試方法失敗
如果是多個斷言依次執(zhí)行,只要前面的斷言不通過,后面的就不會再執(zhí)行了
1、簡單斷言
- assertEquals:判斷兩個對象或兩個原始類型是否相等
- assertNotEquals:判斷兩個對象或兩個原始類型是否不相等
- assertSame:判斷兩個對象引用是否指向同一個對象
- assertNotSame:判斷兩個對象引用是否指向不同的對象
- assertTrue:判斷給定的布爾值是否為 true
- assertFalse:判斷給定的布爾值是否為 false
- assertNull:判斷給定的對象引用是否為 null
- assertNotNull:判斷給定的對象引用是否不為 null
2、數(shù)組斷言
通過 assertArrayEquals 方法來判斷兩個對象或原始類型的數(shù)組是否相等
3、組合斷言
通過assertAll方法接受多個函數(shù)式接口的實例作為要驗證的斷言,只要有一個不通過,就算失敗
4、異常斷言
通過assertThrow方法斷定某個代碼會拋出指定異常
5、超時異常
通過assertTimeout斷定某個代碼的執(zhí)行時間會超過限制時間
6、快速失敗
通過fail方法直接使得測試失敗
package com.decade; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.time.Duration; import java.time.temporal.ChronoUnit; @DisplayName("測試類為TestAssert") public class TestAssert { @Test @DisplayName("測試普通斷言") public void testSimpleAssert() { Assertions.assertEquals(6, 2+3, "期望值與實際值不符"); Assertions.assertTrue(1 > 2, "條件不成立"); Object a = new Object(); Object b = new Object(); Assertions.assertSame(a, b, "不是同一個對象"); } @Test @DisplayName("測試數(shù)組斷言") public void testArray() { Assertions.assertArrayEquals(new int[]{1, 2}, new int[]{2,1}, "數(shù)組不相等"); } @Test @DisplayName("測試組合斷言") public void testCombination() { Assertions.assertAll("斷言組合1", () -> Assertions.assertTrue(1 < 2, "判斷條件不成立"), () -> Assertions.assertEquals(2, 3, "期望值與實際值不相符")); } @Test @DisplayName("測試異常斷言") public void testException() { Assertions.assertThrows(ArithmeticException.class, () -> { System.out.println(1/0); }, "并沒有拋出算數(shù)異常"); } @Test @DisplayName("測試超時斷言") public void testTimeOut() { Assertions.assertTimeout(Duration.of(100, ChronoUnit.MILLIS), () -> Thread.sleep(500), "超時"); } @Test @DisplayName("測試快速失敗fail") public void shouldFail() { Assertions.fail("This should fail"); } }
三、前置條件
前置和斷言的不同之處在于,不滿足的斷言會使得測試方法失敗,而不滿足的前置條件只會使得測試方法的執(zhí)行終止
前置條件可以看成是測試方法執(zhí)行的前提,當該前提不滿足時,就沒有繼續(xù)執(zhí)行的必要
package com.decade; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @DisplayName("測試類為Test") public class Test { @Test @DisplayName("測試前置條件") public void testAssumptions() { Assumptions.assumeTrue(1 > 2, "條件不成立,后續(xù)步驟不再執(zhí)行"); System.out.println("前置條件成立,繼續(xù)執(zhí)行到此步驟"); } }
四、嵌套測試
可以理解成測試套娃,需要注意的是,外層的測試方法無法驅(qū)動內(nèi)層的測試方法,去執(zhí)行內(nèi)層測試方法的beforeEach、beforeAll、afterEach、afterAll
package com.decade; import org.junit.jupiter.api.*; import java.util.EmptyStackException; import java.util.Stack; @DisplayName("進行嵌套測試") public class TestAStackDemo { Stack<Object> stack; @Test @DisplayName("is instantiated with new Stack()") void isInstantiatedWithNew() { new Stack<>(); // 外層的test方法無法驅(qū)動內(nèi)層的test,也就無法驅(qū)動下方的BeforeEach去實例化stack,所以這里會報空 Assertions.assertNull(stack); } @Nested @DisplayName("when new") class WhenNew { @BeforeEach void createNewStack() { stack = new Stack<>(); } @Test @DisplayName("is empty") void isEmpty() { Assertions.assertTrue(stack.isEmpty()); } @Test @DisplayName("throws EmptyStackException when popped") void throwsExceptionWhenPopped() { Assertions.assertThrows(EmptyStackException.class, stack::pop); } @Test @DisplayName("throws EmptyStackException when peeked") void throwsExceptionWhenPeeked() { Assertions. assertThrows(EmptyStackException.class, stack::peek); } @Nested @DisplayName("after pushing an element") class AfterPushing { String anElement = "an element"; // 內(nèi)層的test可以驅(qū)動外層的test,這里會驅(qū)動上方的beforeEach去實例化stack @BeforeEach void pushAnElement() { stack.push(anElement); } @Test @DisplayName("it is no longer empty") void isNotEmpty() { Assertions.assertFalse(stack.isEmpty()); } @Test @DisplayName("returns the element when popped and is empty") void returnElementWhenPopped() { Assertions.assertEquals(anElement, stack.pop()); Assertions.assertTrue(stack.isEmpty()); } @Test @DisplayName("returns the element when peeked but remains not empty") void returnElementWhenPeeked() { Assertions.assertEquals(anElement, stack.peek()); Assertions.assertFalse(stack.isEmpty()); } } } }
五、參數(shù)化測試
- @ValueSource: 為參數(shù)化測試指定入?yún)碓?,支持八大基礎類以及String類型,Class類型
- @NullSource: 表示為參數(shù)化測試提供一個null的入?yún)?/li>
- @EnumSource: 表示為參數(shù)化測試提供一個枚舉入?yún)?/li>
- @CsvFileSource:表示讀取指定CSV文件內(nèi)容作為參數(shù)化測試入?yún)?/li>
- @MethodSource:表示讀取指定方法的返回值作為參數(shù)化測試入?yún)?注意方法返回需要是一個流)
package com.decade; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import java.util.stream.Stream; @DisplayName("進行參數(shù)化測試") public class Test { @ParameterizedTest @ValueSource(strings = {"decade", "hhh", "LOL"}) @DisplayName("參數(shù)化測試,傳入String類型依次測試") public void testParameter(String variables) { System.out.println(variables); } @ParameterizedTest // 此處為方法名,方法必須返回stream流,并且是靜態(tài)的 @MethodSource("creatStream") @DisplayName("參數(shù)化測試,傳入String類型依次測試") public void testParameterIsMethod(String variables) { System.out.println(variables); } static Stream<String> creatStream() { return Stream.of("decade", "hhh", "basketball"); } }
測試結(jié)果如圖
到此這篇關于SpringBoot實現(xiàn)單元測試示例詳解的文章就介紹到這了,更多相關SpringBoot單元測試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot實現(xiàn)RabbitMQ監(jiān)聽消息的四種方式
本文主要介紹了SpringBoot實現(xiàn)RabbitMQ監(jiān)聽消息的四種方式,包括@RabbitListener,MessageListener接口,MessageListenerAdapter適配器,@RabbitHandler這幾種,感興趣的可以了解一下2024-05-05Java Swing實現(xiàn)坦克大戰(zhàn)游戲
這篇文章主要介紹了Java Swing實現(xiàn)坦克大戰(zhàn)游戲,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有很大的幫助喲,需要的朋友可以參考下2021-05-05