javascript
SpringBoot2 集成测试组件,七种测试手段对比
一、背景描述
在版本開發中,時間段大致的劃分為:需求,開發,測試;
- 需求階段:理解需求做好接口設計;
- 開發階段:完成功能開發和對接;
- 測試上線:自測,提測,修復,上線;
實際上開發階段兩個核心的工作,開發和流程自測,自測的根本目的是為自己提前解決可能出現的問題;如果缺少自測和提測兩個關鍵步驟,那么問題就會被傳遞給更多的用戶,產生更多的資源消耗;
自測是于開發而言,提測是對專業的測試人員而言,如果盡可能在自測階段就發現問題,并解決問題,那么一個問題就不會影響到團隊協作上的更多人員,如果一個簡單的問題上升到團隊協作層面,很可能會導致問題本身被放大。
工欲善其事必先利其器,開發如果要做好自測流程,學會使用工具提高效率是十分關鍵的,自測的關鍵在于發現問題和解決問題,所以選擇好用和高效的工具可以極大的降低自測的時間消耗。
下面圍繞幾個自己開發過程中常用的測試工具和手段,做簡單的總結,不在于對比方式的好壞,存在即合理,在不同場景中對合理手段的選擇,快速解決問題才是根本目的。
二、PostMan工具
PostMan很常用的接口測試工具,開發過程中快速測試接口,功能強大并且簡單方便,不但可以單個接口測試,也可以對接口分塊管理批量運行:
整體來說工具比較好用,適應于開發階段的接口快速測試,或者在解決問題的過程中單個接口的測試,同時對測試參數有存儲和記憶能力,這也是受歡迎的一大原因。
但是該工具不適應于復雜的流程化測試,例如需要根據上次接口的響應報文做分別處理,或者下次請求需要填充某個接口響應的數據。
三、Swagger文檔
Swagger管理接口文檔,是當下服務中很常用的組件,通過對接口和對象的簡單注釋,快速生成接口描述信息,并且可以對接口發送請求,協助調試,該文檔在前后端聯調中極大的提高效率。
接口文檔的管理本身是一件麻煩事,接口通常會根據業務不斷的調整,如果單獨維護一份接口文檔,需要付出很多時間成本,并且容易出問題,利用swagger就可以避免這個問題。
借助swagger注解標記對象
@TableName("jt_activity") @ApiModel(value="活動PO對象", description="活動信息表【jt_activity】") public class Activity {@ApiModelProperty(value = "主鍵ID")@TableId(type = IdType.AUTO)private Integer id;@ApiModelProperty(value = "活動主題")private String activityTitle;@ApiModelProperty(value = "聯系號碼")private String contactPhone;@ApiModelProperty(value = "1線上、2線下")private Integer isOnline;@ApiModelProperty(value = "舉辦地址")private String address;@ApiModelProperty(value = "主辦單位")private String organizer;@ApiModelProperty(value = "創建時間")private Date createTime; }借助swagger注解標記接口
@Api(tags = "活動主體接口") @RestController public class ActivityWeb {@Resourceprivate ActivityService activityService ;@ApiOperation("新增活動")@PostMapping("/activity")public Integer save (@RequestBody Activity activity){activityService.save(activity) ;return activity.getId() ;}@ApiOperation("主鍵查詢")@GetMapping("/activity/{id}")public Activity getById (@PathVariable("id") Integer id){return activityService.getById(id) ;}@ApiOperation("修改活動")@PutMapping("/activity")public Boolean updateById (@RequestBody Activity activity){return activityService.updateById(activity) ;} }通常來說,基于swagger注解標記接口類和方法上的入參和關鍵返參對象即可,這樣可以避免再單獨維護接口文檔。
Swagger接口文檔在開發的過程中更多是扮演文檔的角色,真正使用swagger去調試的接口也常是一些增刪改查的簡單接口,這個工具也同樣不適應于復雜流程的測試。
四、TestRestTemplate類
SpringBoot測試包中集成的測試API,需要依賴測試包,可以訪問控制層接口,非常方便的完成交互過程:
Jar包依賴
<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) ;@Resourceprivate TestRestTemplate restTemplate;private Activity activity = null ;@Beforepublic void before (){activity = restTemplate.getForObject("/activity/{id}", Activity.class,1);logger.info("\n"+JSONUtil.toJsonPrettyStr(activity));}@Testpublic void updateById (){if (activity != null){activity.setCreateTime(new Date());activity.setOrganizer("One商家");restTemplate.put("/activity",activity);}}@Afterpublic void after (){activity = restTemplate.getForObject("/activity/{id}", Activity.class,1);logger.info("\n"+JSONUtil.toJsonPrettyStr(activity));activity = null ;} }在TestRestTemplate源碼中可以發現,基于RestTemplate做封裝,很多功能的實現都是調用RestTemplate方法。
用寫代碼的方式去實現接口測試,靈活度非常高,可以根據流程做定制開發,很適應于中等復雜的場景測試,這里為什么這樣描述,下面對比Http請求再細說。
五、Http請求模式
通過模擬接口的Http請求實現的方式,目前來說個人感覺靈活的最高的方式,先看簡單的案例:
@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 = "服務地址+端口";@Testpublic void testHttp (){// 查詢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);} }這種方式對于復雜的業務流程來說非常好用,當然這里不排除個人習慣,在測試復雜流程的時候,一個簡單方案:
- 用戶信息:模擬http中token數據;
- 業務流程:通過數據獲取包裝參數模型;
- 獨立服務管理,模擬并發場景;
- 根據執行過程生成分析數據結果;
對于復雜業務流程的測試,每個節點的模擬都具有一定的難度,通常在完整的流程中涉及到的服務和庫表都是多個,并且請求鏈路復雜,基于一個靈活的自動化流程,去測試完整的鏈路,可以對效率有極大的提升。
六、Service層測試
針對服務層的測試手段,其本意在于業務實現的邏輯測試:
@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class ActivityTest04 {protected static Logger logger = LoggerFactory.getLogger(ActivityTest04.class) ;@Autowiredprivate ActivityService activityService ;@Testpublic void testService (){// 查詢Activity activity = activityService.getById(1) ;// 新增activity.setId(null);activityService.save(activity) ;// 修改activity.setOrganizer("Ser商家");activityService.updateById(activity) ;// 刪除activityService.removeById(activity.getId()) ;} }該測試在實際的開發過程也并不常用,偶爾在于某個業務方法實現難度很大,用來針對性測試。
七、MockMvc方式
MockMvc同樣是SpringBoot集成測試包提供的測試方式,通過對象的模擬,驗證接口是否符合預期:
@AutoConfigureMockMvc @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) public class ActivityTest02 {protected static Logger logger = LoggerFactory.getLogger(ActivityTest02.class) ;@Resourceprivate MockMvc mockMvc ;private Activity activity = null ;@Beforepublic 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) ;}@Testpublic 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);}@Afterpublic 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);} }對于這種Mock類型的測試,非常專業,通常個人使用極少,暫時沒有Get到其精髓思想。
八、Mockito測試
Mock屬于非常專業和標準的測試手段,需要依賴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>簡單使用案例:
@RunWith(PowerMockRunner.class) @SpringBootTest public class ActivityTest05 {@Testpublic void testMock (){Set mockSet = PowerMockito.mock(Set.class);PowerMockito.when(mockSet.size()).thenReturn(10);int actual = mockSet.size();int expected = 15 ;Assert.assertEquals("返回值不符合預期",expected, actual);}@Testpublic 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);} }可以通過Mock方式,快速模擬出復雜的對象結構,以便構建測試方法,由于使用很少,同樣個人暫時沒Get到點。
九、源代碼地址
GitHub·地址 https://github.com/cicadasmile/middle-ware-parent GitEE·地址 https://gitee.com/cicadasmile/middle-ware-parent閱讀標簽
【Java基礎】【設計模式】【結構與算法】【Linux系統】【數據庫】
【分布式架構】【微服務】【大數據組件】【SpringBoot進階】【Spring&Boot基礎】
【數據分析】【技術導圖】【 職場】
總結
以上是生活随笔為你收集整理的SpringBoot2 集成测试组件,七种测试手段对比的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]互联网产品经理必上的九个资讯+分析
- 下一篇: Dreamweaver中如何格式化代码