同事这样做接口校验,两天就完成了OKR

​一、背景:

接口自动化是一种能提高服务回归效率,保证服务稳定性的重要方式。但是对很多做接口自动化的测试来说,往往痛苦大于快乐。主要问题还是在于接口自动化的校验。

  • 写校验成本较高。很多接口响应字段可能非常多,结构体复杂,要做到详细校验编写成本很高。而越详细的校验,维护成本也越高。测试数据的变动,开发的改造,往往能让人崩溃。
  • 校验不够详细。很多接口case为了急于求成没有写返回校验,或者校验深度不够,这会导致接口自动化流于形式,不能发挥真正的作用;

基于此,希望有一个快速编写接口响应校验的方法,要求简单、便捷、有效、可维护性高。

本以为接口自动化大家都在做,通用的响应校验网上应该有很多现成的,但是找了下却没有找到满意的。通用的json校验有,但是接口响应未必都是json格式的。DeepDiff在功能上基本满足要求,但是它是python的,而本人需要的是java的。

基于此,就考虑自己封装出一个基于java的通用的接口响应校验方法,降低接口响应校验的编写和维护成本。

二、实现:

使用java编写,响应校验实现逻辑大致如下。入参这里actualResp是实际的接口响应,exceptResp是期望的接口响应。

2.1 主要功能点

1.响应的格式多种多样,需要做好兼容。主要返回格式有json、jsonArray、string、list等格式。

2.json格式响应里,里面可能嵌有JSONArray,JSONArray里面可能还有JSONArray。所以里面还有不少判断,递归和循环调用逻辑。

例如cmpJsonObject的主要代码如下

cmpJsonArray的主要代码如下

3.有的json是转义后以String的方式返回的,甚至可能转义后作为某一个字段的值。所以需要一个简单的去转移逻辑。

4.有的字段希望有,但是值是动态的,不希望校验

具体看代码,不一一赘述。

2.2 实现效果

只需assertTrue(ApiRespCompareUtil.cmpResp(actualResp, "期望返回内容"))就可完成期望结果的校验,分分钟完成接口校验编写。当前,只要期望的响应和实际的响应体格式一致,且期望响应是实际响应的子集,则可检验通过。

例如下面这个case,只需要将真实响应进行改造,不需要关心的字段删除,不需要关心值的改为"testNotCare",值是变动字符串的取稳定的字符,value是变动数值的改为">=0",则可将之作为一个响应校验题。

三、上手指南

1. 将ApiRespCompareUtil.java文件放入工程,即可使用。下载地址:

https://github.com/luomantester/ApiRespCompareUtil

2. expectResp可以是某个字段,此时校验时会检查整个响应是否包含expectResp字段。例如

assertTrue(ApiRespCompareUtil.cmpResp(actualResp, "userId"))

3. expectResp可以是一个完整的响应

4. expectResp可以是响应的部分字段。但是此时响应结构必须保持完成,层级不能出错。并列的字段或json可以删除一些

简化为只校验

5.key对应的value值是List,可以取原来部分

6.key对应的value值是“,”相连的一系列值,可以取部分

7.响应体是“,”相连的一系列String,可以取部分

8.接口响应只是简单的false或true也可以校验

9.有些字段希望有,但是对值不是很关心,或者值是个变量,怎么弄?设置期望字段值为"testNotCare",则只检验字段是否存在,不校验值

10.响应里面有个字段是数值,且会变化,怎么校验

目前支持>=和==,可根据需要在ApiRespCompareUtil文件cmpJsonObject方法下自己添加

*校验的json最好是压缩格式的。可以格式化处理后再压缩回去。推荐工具:https://www.sojson.com/

四、需要注意的

4.1 对value值有转义的需要特别注意

例子:

{
   "serverData": "{\"privileges\":{\"restMonthCardDays\":-1365,\"monthCardExpireTime\":1539763683000,\"couponCounts\":3597,\"hasOpenMonthCard\":true,\"isVip\":true,\"vipExpireTime\":11963231238000,\"vipExpireTimeStr\":\"119276天\"},\"socialInfo\":{\"focusCounts\":53,\"followerCounts\":99},\"basicInfo\":{\"userId\":****,\"userName\":\"中哥牛逼\",\"userType\":2,\"avatar\":\"https://user-platform-oss.kujiale.com/uat/MGKMGO5MDSGCCAABAAAAAAA8.png\",\"telephone\":\"182********\",\"score\":0,\"snsTypes\":[\"qijia\",\"jd\",\"dou_yin\"],\"everyDaySign\":{\"signed\":false,\"signCounts\":1},\"decoPlan\":1,\"obsUserId\":\"********\"}}"
}

这种层层嵌套的json,比对的时候会去转义进行比较。但是测试在删减字段的时候需要特别注意,确认删减之后的响应体符合json格式。去转义后,也符合json格式。响应结构层级没有变化。

推荐工具:https://www.sojson.com/,可以使用工具将value去转移,筛检处理后,再转义,放回去。处理后:{"serverData":"{\"privileges\":{\"restMonthCardDays\":\"testNotCare\",\"monthCardExpireTime\":\"testNotCare\",\"couponCounts\":\"testNotCare\",\"hasOpenMonthCard\":\"testNotCare\",\"isVip\":true,\"vipExpireTime\":\"testNotCare\",\"vipExpireTimeStr\":\"testNotCare\"},\"socialInfo\":{\"focusCounts\":\">=0\",\"followerCounts\":\">=0\"},\"basicInfo\":{\"userId\":****,\"userName\":\"testNotCare\",\"userType\":2,\"avatar\":\"testNotCare\",\"telephone\":\"testNotCare\",\"score\":0,\"snsTypes\":\"testNotCare\",\"obsUserId\":\"********\"}}"}代码中:

4.2 千万不要什么校验都不写

哪怕接口响应字段都是变量,也建议写个简单兜底的。确保接口是有东西返回的。如

assertTrue(ApiRespCompareUtil.cmpResp(actualResp, "\"c\""));

五、总结

该接口响应通用校验方法的封装意在推动提升组内接口自动化的有效率,目前组内自动化case的有效率已趋近100%,已初步完成了历史case响应校验的完善。该文档编写之初也是为了组内成员可快速上手。

该方法因为自己需要而封装,以实用为主,所以考虑的场景还并不是很全面。好在代码少,结构比较清晰,添加新的校验功能也非常方便。代码已开源,有需要的可以自取,地址:

https://github.com/luomantester/ApiRespCompareUtil,欢迎一起完善。

推荐阅读