springboot集成junit編寫單元測試實戰(zhàn)
在做單元測試時,代碼覆蓋率常常被拿來作為衡量測試好壞的指標,甚至,用代碼覆蓋率來考核測試任務完成情況,比如,代碼覆蓋率必須達到80%或 90%。于是乎,測試人員費盡心思設計案例覆蓋代碼。用代碼覆蓋率來衡量,有利也有弊。
首先,讓我們先來了解一下所謂的“代碼覆蓋率”。我找來了所謂的定義:代碼覆蓋率 = 代碼的覆蓋程度,一種度量方式。
一:查看jar包版本號是否為junit4;
junit自身注解:
@BeforeClass 全局只會執(zhí)行一次,而且是第一個運行 @Before 在測試方法運行之前運行 @Test 測試方法 @After 在測試方法運行之后允許 @AfterClass 全局只會執(zhí)行一次,而且是最后一個運行 @Ignore 忽略此方法
坑:為什么要先看版本號因為在junit5中@Before無效需要使用@BeforeEach;
二:實戰(zhàn)應用:
idea快捷創(chuàng)建測試類:
1.首先要保證有test類,和main同級:
2.創(chuàng)建
編輯
添加圖片注釋,不超過 140 字(可選)
3.編寫單元測試
@RunWith(SpringRunner.class):運行器指定 @SpringBootTest(classes =IotSystemApplication.class, webEnvironment =SpringBootTest.WebEnvironment.DEFINED_PORT) @Slf4j
可選參數(shù)
@ActiveProfiles("baseline") :表示項目啟動參數(shù)為-baseline @Transactional :回滾
import com.shimao.iot.common.entity.ResultListVO; import com.shimao.iot.common.entity.ResultVO; import com.shimao.iot.common.model.dict.vo.AreaDictGangVo; import com.shimao.iot.common.model.dict.vo.AreaDictVo; import com.shimao.iot.system.IotSystemApplication; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author zhangtonghao * @create 2022-02-16 11:00 */ @ActiveProfiles("baseline") @RunWith(SpringRunner.class) @SpringBootTest(classes =IotSystemApplication.class, webEnvironment =SpringBootTest.WebEnvironment.DEFINED_PORT) @AutoConfigureMockMvc @Transactional @Slf4j class AreaDictionaryControllerTest { private MockMvc mockMvc; @Autowired private AreaDictionaryController controller; @Autowired private WebApplicationContext webApplicationContext; /*@BeforeEach 初始化數(shù)據(jù) void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); }*/ @Test void getRegionDetail() { ResultListVO<AreaDictGangVo> regionDetail =controller.getRegionDetail(""); System.out.println("======測試成功:" +regionDetail); String name ="華北"; regionDetail =controller.getRegionDetail(name); Assert.assertNotNull(regionDetail); System.out.println("======測試成功:" +regionDetail); } @Test void testGetRegionDetail() { Long areaCode =100001L; ResultVO<AreaDictVo> regionDetail =controller.getRegionDetail(areaCode); Assert.assertNotNull(regionDetail); System.out.println("======測試成功:" +regionDetail); } @Test void getAreaTypeDetails() { Integer areaCode =100001; ResultListVO<AreaDictVo> resultListVO =controller.getAreaTypeDetails(areaCode); Assert.assertNotNull(resultListVO); System.out.println("======測試成功:" +resultListVO); } @Test void getSubrangeDetail() { Long areaCode =100001L; ResultListVO<AreaDictVo> resultListVO =controller.getSubrangeDetail(areaCode); Assert.assertNotNull(resultListVO); System.out.println("======測試成功:" +resultListVO); } @Test void getGangDetail() { Long areaCode =100001L; ResultVO<AreaDictGangVo> resultListVO =controller.getGangDetail(areaCode); Assert.assertNotNull(resultListVO); System.out.println("======測試成功:" +resultListVO); } @Test void findAreaDictList() { Long areaCode =100001L; List<Long> areaCodes =new ArrayList<>(); areaCodes.add(areaCode); List<AreaDictVo> resultListVO =controller.findAreaDictList(areaCodes); Assert.assertNotNull(resultListVO); System.out.println("======測試成功:" +resultListVO); } @Test void findAreaDictParentMap() { Long areaCode =100001L; List<Long> areaCodes =new ArrayList<>(); areaCodes.add(areaCode); Map<Long, AreaDictVo> resultListVO =controller.findAreaDictParentMap(areaCodes); Assert.assertNotNull(resultListVO); System.out.println("======測試成功:" +resultListVO); } @Test void queryProvinceAndCity() { ResultListVO<AreaDictVo> resultListVO =controller.queryProvinceAndCity(); Assert.assertNotNull(resultListVO); } }
4.啟動測試:正常啟動我就不說了說下如何查看覆蓋率啟動
首先需要安裝junit插件,然后啟動:
注意點:其實書寫單元測試沒有什么技巧,只有一個參數(shù)問題;你能保證參數(shù)正確就可以讓測試覆蓋率更高。這都需要看代碼實現(xiàn),所以不用妄想一鍵生成覆蓋率達到百分之80啥的了,不存在的。下面還有一些可用的技巧和講解,著急的可以不用看直接回去寫代碼去了。
三:擴展
某些對象類的單元測試:
/** * 調用VO DTO POJO MODEL等服務通用方法 */ @Test public void testDto() { HeartDtoheartDto = newHeartDto(); testGetAndSet(heartDto); heartDto.toString(); heartDto.equals(newObject()); heartDto.hashCode(); AlllogDtoallLogDto = newAlllogDto(); testGetAndSet(allLogDto); allLogDto.toString(); allLogDto.equals(newObject()); allLogDto.hashCode(); } /** * JavaBean屬性名要求:前兩個字母要么都大寫,要么都小寫 * 對于首字母是一個單詞的情況,要么過濾掉,要么自己拼方法名 * f.isSynthetic()過濾合成字段 */ private static void testGetAndSet(Object t) { try { Class modelClass =t.getClass(); Object obj =modelClass.newInstance(); Field[] fields =modelClass.getDeclaredFields(); for (Fieldf :fields) { if (f.getName().equals("aLike") ||f.isSynthetic()) { continue; } PropertyDescriptorpd = newPropertyDescriptor(f.getName(), modelClass); Methodget =pd.getReadMethod(); Methodset =pd.getWriteMethod(); set.invoke(obj, get.invoke(obj)); } } catch (Exception e) { e.printStackTrace(); } }
斷言列表:
-------------->assertTrue(String message, boolean condition) 要求condition == true -------------->assertFalse(String message, boolean condition) 要求condition == false -------------->assertEquals(String message, XXX expected,XXX actual) 要求expected期望的值能夠等于actual -------------->assertArrayEquals(String message, XXX[] expecteds,XXX [] actuals) 要求expected.equalsArray(actual) -------------->assertNotNull(String message, Object object) 要求object!=null -------------->assertNull(String message, Object object) 要求object==null -------------->assertSame(String message, Object expected, Object actual) 要求expected == actual -------------->assertNotSame(String message, Object unexpected,Object actual) 要求expected != actual -------------->assertThat(String reason, T actual, Matcher matcher) 要求matcher.matches(actual) == true -------------->fail(String message) 要求執(zhí)行的目標結構必然失敗,同樣要求代碼不可達,即是這個方法在程序運行后不會成功返回,如果成功返回了則報錯
代碼覆蓋程度的度量方式是有很多種的,這里介紹一下最常用的幾種:
1. 語句覆蓋(StatementCoverage)
又稱行覆蓋(LineCoverage),段覆蓋(SegmentCoverage),基本塊覆蓋(BasicBlockCoverage),這是最常用也是最常見的一種覆蓋方式,就是度量被測代碼中每個可執(zhí)行語句是否被執(zhí)行到了。這里說的是“可執(zhí)行語句”,因此就不會包括像C++的頭文件聲明,代碼注釋,空行,等等。非常好理解,只統(tǒng)計能夠執(zhí)行的代碼被執(zhí)行了多少行。需要注意的是,單獨一行的花括號{} 也常常被統(tǒng)計進去。語句覆蓋常常被人指責為“最弱的覆蓋”,它只管覆蓋代碼中的執(zhí)行語句,卻不考慮各種分支的組合等等。假如你的上司只要求你達到語句覆蓋,那么你可以省下很多功夫,但是,換來的確實測試效果的不明顯,很難更多地發(fā)現(xiàn)代碼中的問題。
2. 判定覆蓋(DecisionCoverage)
又稱分支覆蓋(BranchCoverage),所有邊界覆蓋(All-EdgesCoverage),基本路徑覆蓋(BasicPathCoverage),判定路徑覆蓋(Decision-Decision-Path)。它度量程序中每一個判定的分支是否都被測試到了。這句話是需要進一步理解的,應該非常容易和下面說到的條件覆蓋混淆。因此我們直接介紹第三種覆蓋方式,然后和判定覆蓋一起來對比,就明白兩者是怎么回事了。
3. 條件覆蓋(ConditionCoverage)
它度量判定中的每個子表達式結果true和false是否被測試到了。
4. 路徑覆蓋(PathCoverage)
又稱斷言覆蓋(PredicateCoverage)。它度量了是否函數(shù)的每一個分支都被執(zhí)行了。這句話也非常好理解,就是所有可能的分支都執(zhí)行一遍,有多個分支嵌套時,需要對多個分支進行排列組合,可想而知,測試路徑隨著分支的數(shù)量指數(shù)級別增加。
到此這篇關于springboot集成junit編寫單元測試實戰(zhàn)的文章就介紹到這了,更多相關springboot junit單元測試內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java并發(fā)之原子性 有序性 可見性及Happen Before原則
一提到happens-before原則,就讓人有點“丈二和尚摸不著頭腦”。這個涵蓋了整個JMM中可見性原則的規(guī)則,究竟如何理解,把我個人一些理解記錄下來。下面可以和小編一起學習Java 并發(fā)四個原則2021-09-09Java Spring開發(fā)環(huán)境搭建及簡單入門示例教程
這篇文章主要介紹了Java Spring開發(fā)環(huán)境搭建及簡單入門示例,結合實例形式分析了spring環(huán)境搭建、配置、使用方法及相關注意事項,需要的朋友可以參考下2017-11-11spring-boot-klock-starter V1.1 主體功能重大更新內容介紹
這篇文章主要介紹了spring-boot-klock-starter V1.1 主體功能重大更新內容描述,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-01-01淺析Java中靜態(tài)代理和動態(tài)代理的應用與區(qū)別
代理模式在我們生活中很常見,而Java中常用的兩個的代理模式就是動態(tài)代理與靜態(tài)代理,這篇文章主要為大家介紹了二者的應用與區(qū)別,需要的可以參考下2023-08-08Springboot如何獲取yml、properties參數(shù)
這篇文章主要介紹了Springboot如何獲取yml、properties參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03