SpringBoot2 集成測(cè)試組件的七種方法
一、背景描述
在版本開(kāi)發(fā)中,時(shí)間段大致的劃分為:需求,開(kāi)發(fā),測(cè)試;
需求階段:理解需求做好接口設(shè)計(jì);
開(kāi)發(fā)階段:完成功能開(kāi)發(fā)和對(duì)接;
測(cè)試上線(xiàn):自測(cè),提測(cè),修復(fù),上線(xiàn);
實(shí)際上開(kāi)發(fā)階段兩個(gè)核心的工作,開(kāi)發(fā)和流程自測(cè),自測(cè)的根本目的是為自己提前解決可能出現(xiàn)的問(wèn)題;如果缺少自測(cè)和提測(cè)兩個(gè)關(guān)鍵步驟,那么問(wèn)題就會(huì)被傳遞給更多的用戶(hù),產(chǎn)生更多的資源消耗;
自測(cè)是于開(kāi)發(fā)而言,提測(cè)是對(duì)專(zhuān)業(yè)的測(cè)試人員而言,如果盡可能在自測(cè)階段就發(fā)現(xiàn)問(wèn)題,并解決問(wèn)題,那么一個(gè)問(wèn)題就不會(huì)影響到團(tuán)隊(duì)協(xié)作上的更多人員,如果一個(gè)簡(jiǎn)單的問(wèn)題上升到團(tuán)隊(duì)協(xié)作層面,很可能會(huì)導(dǎo)致問(wèn)題本身被放大。
工欲善其事必先利其器,開(kāi)發(fā)如果要做好自測(cè)流程,學(xué)會(huì)使用工具提高效率是十分關(guān)鍵的,自測(cè)的關(guān)鍵在于發(fā)現(xiàn)問(wèn)題和解決問(wèn)題,所以選擇好用和高效的工具可以極大的降低自測(cè)的時(shí)間消耗。
二、PostMan工具
PostMan很常用的接口測(cè)試工具,開(kāi)發(fā)過(guò)程中快速測(cè)試接口,功能強(qiáng)大并且簡(jiǎn)單方便,不但可以單個(gè)接口測(cè)試,也可以對(duì)接口分塊管理批量運(yùn)行:
整體來(lái)說(shuō)工具比較好用,適應(yīng)于開(kāi)發(fā)階段的接口快速測(cè)試,或者在解決問(wèn)題的過(guò)程中單個(gè)接口的測(cè)試,同時(shí)對(duì)測(cè)試參數(shù)有存儲(chǔ)和記憶能力,這也是受歡迎的一大原因。
但是該工具不適應(yīng)于復(fù)雜的流程化測(cè)試,例如需要根據(jù)上次接口的響應(yīng)報(bào)文做分別處理,或者下次請(qǐng)求需要填充某個(gè)接口響應(yīng)的數(shù)據(jù)。
三、Swagger文檔
Swagger管理接口文檔,是當(dāng)下服務(wù)中很常用的組件,通過(guò)對(duì)接口和對(duì)象的簡(jiǎn)單注釋?zhuān)焖偕山涌诿枋鲂畔?,并且可以?duì)接口發(fā)送請(qǐng)求,協(xié)助調(diào)試,該文檔在前后端聯(lián)調(diào)中極大的提高效率。
接口文檔的管理本身是一件麻煩事,接口通常會(huì)根據(jù)業(yè)務(wù)不斷的調(diào)整,如果單獨(dú)維護(hù)一份接口文檔,需要付出很多時(shí)間成本,并且容易出問(wèn)題,利用swagger就可以避免這個(gè)問(wèn)題。
借助swagger注解標(biāo)記對(duì)象
@TableName("jt_activity") @ApiModel(value="活動(dòng)PO對(duì)象", description="活動(dòng)信息表【jt_activity】") public class Activity { @ApiModelProperty(value = "主鍵ID") @TableId(type = IdType.AUTO) private Integer id; @ApiModelProperty(value = "活動(dòng)主題") private String activityTitle; @ApiModelProperty(value = "聯(lián)系號(hào)碼") private String contactPhone; @ApiModelProperty(value = "1線(xiàn)上、2線(xiàn)下") private Integer isOnline; @ApiModelProperty(value = "舉辦地址") private String address; @ApiModelProperty(value = "主辦單位") private String organizer; @ApiModelProperty(value = "創(chuàng)建時(shí)間") private Date createTime; }
借助swagger注解標(biāo)記接口
@Api(tags = "活動(dòng)主體接口") @RestController public class ActivityWeb { @Resource private ActivityService activityService ; @ApiOperation("新增活動(dòng)") @PostMapping("/activity") public Integer save (@RequestBody Activity activity){ activityService.save(activity) ; return activity.getId() ; } @ApiOperation("主鍵查詢(xún)") @GetMapping("/activity/{id}") public Activity getById (@PathVariable("id") Integer id){ return activityService.getById(id) ; } @ApiOperation("修改活動(dòng)") @PutMapping("/activity") public Boolean updateById (@RequestBody Activity activity){ return activityService.updateById(activity) ; } }
通常來(lái)說(shuō),基于swagger注解標(biāo)記接口類(lèi)和方法上的入?yún)⒑完P(guān)鍵返參對(duì)象即可,這樣可以避免再單獨(dú)維護(hù)接口文檔。
Swagger接口文檔在開(kāi)發(fā)的過(guò)程中更多是扮演文檔的角色,真正使用swagger去調(diào)試的接口也常是一些增刪改查的簡(jiǎn)單接口,這個(gè)工具也同樣不適應(yīng)于復(fù)雜流程的測(cè)試。
四、TestRestTemplate類(lèi)
SpringBoot測(cè)試包中集成的測(cè)試API,需要依賴(lài)測(cè)試包,可以訪問(wèn)控制層接口,非常方便的完成交互過(guò)程:
Jar包依賴(lài)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
使用案例
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class ActivityTest01 { protected static Logger logger = LoggerFactory.getLogger(ActivityTest01.class) ; @Resource private TestRestTemplate restTemplate; private Activity activity = null ; @Before public void before (){ activity = restTemplate.getForObject("/activity/{id}", Activity.class,1); logger.info("\n"+JSONUtil.toJsonPrettyStr(activity)); } @Test public void updateById (){ if (activity != null){ activity.setCreateTime(new Date()); activity.setOrganizer("One商家"); restTemplate.put("/activity",activity); } } @After public void after (){ activity = restTemplate.getForObject("/activity/{id}", Activity.class,1); logger.info("\n"+JSONUtil.toJsonPrettyStr(activity)); activity = null ; } }
在TestRestTemplate源碼中可以發(fā)現(xiàn),基于RestTemplate做封裝,很多功能的實(shí)現(xiàn)都是調(diào)用RestTemplate方法。
用寫(xiě)代碼的方式去實(shí)現(xiàn)接口測(cè)試,靈活度非常高,可以根據(jù)流程做定制開(kāi)發(fā),很適應(yīng)于中等復(fù)雜的場(chǎng)景測(cè)試,這里為什么這樣描述,下面對(duì)比Http請(qǐng)求再細(xì)說(shuō)。
五、Http請(qǐng)求模式
通過(guò)模擬接口的Http請(qǐng)求實(shí)現(xiàn)的方式,目前來(lái)說(shuō)個(gè)人感覺(jué)靈活的最高的方式,先看簡(jiǎn)單的案例:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class ActivityTest03 { protected static Logger logger = LoggerFactory.getLogger(ActivityTest03.class) ; protected static String REQ_URL = "服務(wù)地址+端口"; @Test public void testHttp (){ // 查詢(xún) String getRes = HttpUtil.get(REQ_URL+"activity/1"); logger.info("\n {} ",JSONUtil.toJsonPrettyStr(getRes)); Activity activity = JSONUtil.toBean(getRes, Activity.class) ; // 新增 activity.setId(null); activity.setOrganizer("Http商家"); String saveRes = HttpUtil.post(REQ_URL+"/activity",JSONUtil.toJsonStr(activity)); logger.info("\n {} ",saveRes); // 更新 activity.setId(Integer.parseInt(saveRes)); activity.setOrganizer("Put商家"); String putRes = HttpRequest.put(REQ_URL+"/activity") .body(JSONUtil.toJsonStr(activity)).execute().body(); logger.info("\n {} ",putRes); } }
這種方式對(duì)于復(fù)雜的業(yè)務(wù)流程來(lái)說(shuō)非常好用,當(dāng)然這里不排除個(gè)人習(xí)慣,在測(cè)試復(fù)雜流程的時(shí)候,一個(gè)簡(jiǎn)單方案:
- 用戶(hù)信息:模擬http中token數(shù)據(jù);
- 業(yè)務(wù)流程:通過(guò)數(shù)據(jù)獲取包裝參數(shù)模型;
- 獨(dú)立服務(wù)管理,模擬并發(fā)場(chǎng)景;
- 根據(jù)執(zhí)行過(guò)程生成分析數(shù)據(jù)結(jié)果;
對(duì)于復(fù)雜業(yè)務(wù)流程的測(cè)試,每個(gè)節(jié)點(diǎn)的模擬都具有一定的難度,通常在完整的流程中涉及到的服務(wù)和庫(kù)表都是多個(gè),并且請(qǐng)求鏈路復(fù)雜,基于一個(gè)靈活的自動(dòng)化流程,去測(cè)試完整的鏈路,可以對(duì)效率有極大的提升。
六、Service層測(cè)試
針對(duì)服務(wù)層的測(cè)試手段,其本意在于業(yè)務(wù)實(shí)現(xiàn)的邏輯測(cè)試:
@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class ActivityTest04 { protected static Logger logger = LoggerFactory.getLogger(ActivityTest04.class) ; @Autowired private ActivityService activityService ; @Test public void testService (){ // 查詢(xún) Activity activity = activityService.getById(1) ; // 新增 activity.setId(null); activityService.save(activity) ; // 修改 activity.setOrganizer("Ser商家"); activityService.updateById(activity) ; // 刪除 activityService.removeById(activity.getId()) ; } }
該測(cè)試在實(shí)際的開(kāi)發(fā)過(guò)程也并不常用,偶爾在于某個(gè)業(yè)務(wù)方法實(shí)現(xiàn)難度很大,用來(lái)針對(duì)性測(cè)試。
七、MockMvc方式
MockMvc同樣是SpringBoot集成測(cè)試包提供的測(cè)試方式,通過(guò)對(duì)象的模擬,驗(yàn)證接口是否符合預(yù)期:
@AutoConfigureMockMvc @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class ActivityTest02 { protected static Logger logger = LoggerFactory.getLogger(ActivityTest02.class) ; @Resource private MockMvc mockMvc ; private Activity activity = null ; @Before public void before () throws Exception { ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.get("/activity/{id}",1)) ; MvcResult mvcResult = resultAction.andReturn() ; String result = mvcResult.getResponse().getContentAsString(); activity = JSONUtil.toBean(result,Activity.class) ; } @Test public void updateById () throws Exception { activity.setId(null); activity.setCreateTime(new Date()); activity.setOrganizer("One商家"); ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.post("/activity") .contentType(MediaType.APPLICATION_JSON) .content(JSONUtil.toJsonStr(activity))) ; MvcResult mvcResult = resultAction.andReturn() ; String result = mvcResult.getResponse().getContentAsString(); activity.setId(Integer.parseInt(result)); logger.info("result : {} ",result); } @After public void after () throws Exception { activity.setCreateTime(new Date()); activity.setOrganizer("Update商家"); ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.put("/activity") .contentType(MediaType.APPLICATION_JSON) .content(JSONUtil.toJsonStr(activity))) ; MvcResult mvcResult = resultAction.andReturn() ; String result = mvcResult.getResponse().getContentAsString(); logger.info("result : {} ",result); } }
對(duì)于這種Mock類(lèi)型的測(cè)試,非常專(zhuān)業(yè),通常個(gè)人使用極少,暫時(shí)沒(méi)有Get到其精髓思想。
八、Mockito測(cè)試
Mock屬于非常專(zhuān)業(yè)和標(biāo)準(zhǔn)的測(cè)試手段,需要依賴(lài)powermock包:
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <scope>test</scope> </dependency>
簡(jiǎn)單使用案例:
@RunWith(PowerMockRunner.class) @SpringBootTest public class ActivityTest05 { @Test public void testMock (){ Set mockSet = PowerMockito.mock(Set.class); PowerMockito.when(mockSet.size()).thenReturn(10); int actual = mockSet.size(); int expected = 15 ; Assert.assertEquals("返回值不符合預(yù)期",expected, actual); } @Test public void testTitle (){ String expectTitle = "Mock主題" ; Activity activity = PowerMockito.mock(Activity.class); PowerMockito.when(activity.getMockTitle()).thenReturn(expectTitle); String actualTitle = activity.getMockTitle(); Assert.assertNotEquals("主題相符", expectTitle, actualTitle); } }
可以通過(guò)Mock方式,快速模擬出復(fù)雜的對(duì)象結(jié)構(gòu),以便構(gòu)建測(cè)試方法,由于使用很少,同樣個(gè)人暫時(shí)沒(méi)Get到點(diǎn)。
九、源代碼地址
GitHub·地址
https://github.com/cicadasmile/middle-ware-parent
GitEE·地址
https://gitee.com/cicadasmile/middle-ware-parent
以上就是SpringBoot2 集成測(cè)試組件的七種方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot2 集成測(cè)試組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- springboot集成測(cè)試容器重啟問(wèn)題的處理
- 基于SpringBoot集成測(cè)試遠(yuǎn)程連接Redis服務(wù)的教程詳解
- Spring Boot 單元測(cè)試和集成測(cè)試實(shí)現(xiàn)詳解
- springboot項(xiàng)目中引入本地依賴(lài)jar包并打包到lib文件夾中
- 一篇文章徹底弄懂SpringBoot項(xiàng)目jdk版本及依賴(lài)不兼容問(wèn)題
- SpringBoot項(xiàng)目依賴(lài)和配置最新示例講解
- SpringBoot快速入門(mén)及起步依賴(lài)解析(實(shí)例詳解)
- springboot集成測(cè)試最小化依賴(lài)實(shí)踐示例
相關(guān)文章
datatables 帶查詢(xún)條件java服務(wù)端分頁(yè)處理實(shí)例
本篇文章主要介紹了datatables 帶查詢(xún)條件java服務(wù)端分頁(yè)處理實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Java高效提取PDF文件指定坐標(biāo)的文本內(nèi)容實(shí)戰(zhàn)代碼
在日常工作中,有時(shí)可能會(huì)需要從龐大的PDF文檔中提取其中所包含的文本內(nèi)容,下面這篇文章主要給大家介紹了關(guān)于如何利用Java高效提取PDF文件指定坐標(biāo)的文本內(nèi)容,需要的朋友可以參考下2024-01-01maven多moudle項(xiàng)目在idea里面顯示多個(gè)root問(wèn)題及解決
這篇文章主要介紹了maven多moudle項(xiàng)目在idea里面顯示多個(gè)root問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05jdk中keytool的使用以及如何提取jks文件中的公鑰和私鑰
JKS文件由公鑰和密鑰構(gòu)成利用Java?Keytool工具生成的文件,它是由公鑰和密鑰構(gòu)成的,下面這篇文章主要給大家介紹了關(guān)于jdk中keytool的使用以及如何提取jks文件中公鑰和私鑰的相關(guān)資料,需要的朋友可以參考下2024-03-03Springboot項(xiàng)目中單元測(cè)試時(shí)注入bean失敗的解決方案
這篇文章主要介紹了Springboot項(xiàng)目中單元測(cè)試時(shí)注入bean失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11SpringBoot實(shí)現(xiàn)MapperScan添加動(dòng)態(tài)配置(占位符)
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)MapperScan添加動(dòng)態(tài)配置(占位符),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01詳解springMVC兩種方式實(shí)現(xiàn)多文件上傳及效率比較
本篇文章介紹了springMVC兩種方式實(shí)現(xiàn)多文件上傳及效率比較。springMVC實(shí)現(xiàn)多文件上傳有兩種,一種是字節(jié)流的方式進(jìn)行文件上傳,另外一種是使用springMVC包裝好的解析器進(jìn)行上傳,有興趣的可以了解一下。2016-12-12Java緩存Map設(shè)置過(guò)期時(shí)間實(shí)現(xiàn)解析
這篇文章主要介紹了Java緩存Map設(shè)置過(guò)期時(shí)間實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Intellij IDEA 錄制快捷鍵實(shí)現(xiàn)自動(dòng)格式化的方法
這篇文章主要介紹了Intellij IDEA 錄制快捷鍵實(shí)現(xiàn)自動(dòng)格式化的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09