🎉 🎂 🍰 TesterHome 创立 6 周年纪念日 🍰 🎂 🎉

接口测试 搞定接口测试变态要求:海量接口返回值对比验证

zyanycall · 2018年08月01日 · 最后由 niezp 回复于 2018年09月19日 · 6662 次阅读
本帖已被设为精华帖!

上半年我给自己挖了个坑,说海量接口返回值比对是接口测试的核心要求之一,这次来说一下我是怎么做的。
做一下必要的铺垫,也顺带说一下测试的工作方式,各位看着高兴最好。
每个公司遇到的需求及问题都是不同的,大家还要因地制宜。

背景

公司最近搞了一个新项目,既实现了新的代码同时也复用了老的环境。
而复用老环境时,某核心开发因为看不下去老的代码(确实)太烂,打算借此机会重构老代码,一波上线。

开发的测试要求

希望老系统代码重构后,接口返回值没有变化。
涉及接口超过100个,几乎都是读接口。
回归测试强度,即核心业务逻辑没有改动,是代码结构的变动。仅观察返回值结构等是否一样即可。
可以提供原有环境及新环境,便于对比。
时间紧迫,要1天内搞定。
接口数量太多,影响较大,测试要认真对待。

测试的疑问

为什么现在才提重构老代码的事儿。
老代码重构和新代码上线不能混为一谈,新代码上线是雪中送炭,老代码重构是锦上添花。
无法理解为什么要一波上线,老代码重构可以慢慢搞,没必要一起上。
时间太紧迫。
接口数量太多,能否缩减范围。

开发的答复

重构老代码是某核心开发自己搞的,确实不在需求之中。
老代码重构势在必行,实在看不下去了,并且新代码上线后压力会大,担心有问题。
其实之前已经有部分重构代码上线了,但线上出了问题,所以后面的涉及重构的都需要验证测试。
新老代码混合程度较高,单独摘除老代码重构成本不小,时间消耗上摘除和一起上线差不多(反正已经上了一部分了)。
开发较自信(线上打脸了才想起来测试?),到现在还是很自信,重构没啥问题。
所以之前没测试重构,说重构了也担心不允许,那这些老代码会一直烂下去。
测试帮帮忙,相信你。

我的思考

我非常理解核心开发重构代码的动机。
这是个展现测试价值的好机会,如果你们开发能搞定就不会来找我了。
开发没办法搞定也没时间搞定了(线上bug修改等事情很多),时间紧迫。

此时此刻只有我才能搞定这件事儿(自带特效字带背景音乐自带慢动作)。

我的底气

接口测试用例数据,这个是接口测试独有的,也是让这一切可执行的基础。
我开发的各种工具。

完成任务的方式

  1. 手工执行100多个接口,然后新老环境各执行一遍,之后使用beyond compare 比对一遍。(这不是让开发看笑话吗?也可能开发的预期就是这样,所以没时间搞)。
  2. 将任务1分工下去,比如测试方出5个人,开发出5个人,每人10多个接口,手工执行,比对,汇总结果。(需要牵头人,体现领导才能?但是任务会上升,牵头人未必是我)。
  3. 自动化执行100多个接口,然后手工拷贝每个接口的返回值,两次自动化后beyond compare比对。 存在的问题: 1) 接口返回值非常长,即便是软件比对,细节也看不清,返回值需要格式化。 2) 拷贝结果要执行100多次,要执行两遍,非常非常繁琐麻烦和累。如果一遍比对不成功那画面太美。 3) 如何有效执行100个多接口。
  4. 必须自动化执行。

自动化执行的方式

  1. 完全代码实现,比如测试用例数据保存在数据库中,代码首先读取数据库,然后依次执行每个接口,将所有的返回值汇总并格式化输出成文档,一键拷贝比对即可。
  2. Jmeter + Ant 再加工实现,读取数据库使用beanshell,依次执行每个接口使用Jmeter自带功能即可,结合Ant产生测试报告文件就是测试结果文档。

  3. 完全代码实现是可行的,我也实现了,但不是为了这种比对场景做的,是为了边界测试(后续可能分享挖坑)。

  4. Jmeter + Ant 需要再加工,比如测试报告中结果的格式化,测试报告的文档拷贝的一键执行,我实现了这些,今天讲这些。

  5. Jmeter + Ant 在此次场景下,是最方便的,因为我之前实现了很多功能,就为了这种硬仗准备的。

Jmeter + Ant测试工具的二次开发

上面已经简述了任务要完成需要做的,再汇总一下:

  1. Jmeter脚本要读取数据库,获得这100多个接口的接口测试用例数据,然后可以脚本执行。这种执行可以切换新老环境,达到新老环境每个都执行一遍的基本要求。
  2. Ant 运行Jmeter脚本后,会生成html格式的测试报告,但是需要将测试报告中的返回值格式化(JSON格式化)。
  3. html格式的测试报告,要有一键获取所有格式化的测试结果的功能,这样才能高效的复制出来这100多个接口的返回结果,才能比对。

Jmeter脚本如何读取数据库并执行所需要的用例

这里就口述一下了,简单贴图,毕竟详述太费劲。

  1. 通过SQL语句,筛选获取测试用例的主键ID集合,比如(100,101,102,103,104),同时获取数量,比如总数为5,都保存为自定义变量。
  2. 使用Jmeter的循环控制器,循环的次数就是上面第一步获取的数量,循环5次。

  3. 在每个循环中,从主键ID集合中从头拿ID,比如拿到100这个ID,记录数组下标为0,保存数组下标为自定义变量,根据100这个ID获取的所有的接口测试数据定义为自定义变量。

  4. 根据上面第三步获得的数据,来执行HTTP Sampler,真正的发出请求。

html格式的测试报告如何格式化

我改造的是最流行的 jmeter.results.shanhe.me.xsl 结果模板。
这个已经放到CSDN下载上去了,我上传的,代码我也就不详细贴了,毕竟说起来很麻烦,说一下当时解决的思路。

  1. xsl我找资料查了下,是一种生成html的模板,里面包含各种函数逻辑,是可以同时有js代码和html标签结构的。
  2. 既然是js和html标签,那么我需要在网上找一个格式化JSON的js代码,将其嵌入到这个模板中就好。
  3. 我认为,hmtl文档中保存的是非格式化的数据,左侧超链接单击时,触发格式化js代码可行,这样html文件最小。
  4. 难点是,如何唯一标识每一个返回值,唯一标识后,才能单击哪个格式化哪个,才能找到数据。

然后我都搞定了。

如何一键获取所有格式化的测试结果

我继续加工上面的 jmeter.results.shanhe.me.xsl 结果模板。
思路:

  1. 找到一个触发条件,循环所有的上面已经格式化好的结果集合,找地方都存起来。
  2. 最好是一键下载,比如我打开html文件,点一下,提示我下载,最方便。可惜,由于浏览器出于对数据的保护,不允许下载,执行这种操作,生成文本都不允许。
  3. 使用console.log方式,将这些结果都打印到日志中,浏览器开发者模式下,全选拷贝出来,用于比对。

结尾

我当然解决了测试任务,并且开发再次被打脸,重构的问题还是很多的。
收到了表扬信。

讨论一下Jmeter + Ant和完全自己开发的优势

  1. Jmeter + Ant 可以再 + Jenkins ,这是持续集成,完全自己开发要做到这些,工作量还是有不少的。
  2. Jmeter + Ant 已经有了,已经满足了很多要求,没必要再造轮子了。
  3. Jmeter + Ant 最核心的Jmeter,功能太丰富了,比如正则表达式,自定义变量,参数化,性能测试,定时执行等等。 这基本满足所有复杂的接口测试要求,自开发这些工具真的比不了。
  4. 接口返回值的mock,不在此讨论之列。
共收到 43 条回复 时间 点赞

没有单元测试保证的重构都是耍流氓,开发重构之前需要学习一下如何编写单元测试(或许你身边有一堆不知道如何编写单元测试)。

楼主用jmeter处理有点复杂,如果仅检查返回码,一个连数据库的函数+一个循环便可解决问题。

JS应该有集成好的JsonSchema可以直接用吧

beyond compare有命令行的执行方式,输出的报告也很直观

Twitter :Diffy 是否可以满足啊

既然是海量,那么
男儿何不带mapping,直接测试DB层?
接口测试就那么好玩吗……

iqianxing 回复

不仅仅是测试返回码啊~返回值的格式,甚至大小写匹配,返回值的key value 都要一致的。

BugaoxingXXX 回复

这个地方主要是对比测试,两个环境海量接口返回值的对比测试。
Json Schema明显是没做的……你的建议很好,不过很难推行。

watchdog 回复

beyond compare命令行没用过, 能把JSON格式化后再对比吗?

lovoro 回复

不了解这么高端的工具。

fudax 回复

接口返回值可以包含多个表的数据,再说接口可能有缓存的,都不调用DB的数据,直接测试数据库是不行的。

看了看diffy介绍,感觉可以用来解决你的问题。

oggboy 回复

diffy是个好工具啊,界面也不错。应该可以搞定我的问题,即便搞不定二次开发的工作量也比较小,主要是这测试结果是在线的很赞。

zyanycall 回复

我比较感兴趣的是重构如何影响字段的大小写了?

zyanycall 回复

此外大小写是否一样在for循环加上一个断言便可解决

可以看下我这篇文章,早就写好你想要的比对了
接口测试 [JsonSchema] 关于接口测试 Json 格式比对核心算法实现 (Java 版) https://testerhome.com/topics/9252

hu_qingen 回复

不错,学习了。

iqianxing 回复

你的一个连数据库的函数+一个循环 再加上 @hu_qingen 的接口测试 [JsonSchema] 关于接口测试 Json 格式比对核心算法实现 (Java 版) 这应该就是你写的 “一个断言” 的完整实现。

至于重构怎么改变大小写了,你很感兴趣……可能测试的工作就是这样吧,面对的是各种各样的问题。
没别的意思,我觉得我的这篇至少引发了你对解决问题的思考,并且你也感兴趣了,我觉得就很好。

seveniruby 将本帖设为了精华贴 08月02日 15:49

twitter的diffy其实是可以的。

hu_qingen 回复

schema还不行,schema校验只是校验目标字段的范围,还是有点笼统,使用diffy这类的方案是最好的。楼主写的也不错

seveniruby 回复

谢谢版主肯定。

zyanycall 回复

1、在python、node.js中json对比真实的就是一个断言实现,Java用得少,但我相信已有开源的已实现对比的jar包;
2、重构代码过程中开发将请求参数、响应结果的大小写修改了,我只是对这个开发表示佩服。

seveniruby 回复

我去看下,😀

返回的断言处理我这边分为 第一是验证长度&检查几层的json,长度可以判断是否是有效的和是否是失效的。检查几层在于第n层 value 检查是不是字典,第n-1层一层层递归检查。
第二个是验证参数key是否包含和value是否在包含。用封装的断言库。

zyanycall 回复

你可以自己格式化json之后,使用beyond compare对比

watchdog 回复

好的。我文中就是这么做的。

自己用python做了个简单的接口验证,get/post请求,返回结果检查,感觉适合大批量运行。jmeter只用过性能测试,配置参数循环还是挺方便的。

seveniruby 回复

请问diffy 有相关的实战使用经验文档吗?

想请问下楼主,返回的数据进行对比验证前是怎么做json排序的啊?

hshj1989 回复

使用mocha,一个for循环可以搞定,json对比字段是由chai内部实现的,可以不用关注。
参见:接口测试过程中如何快速进行 diff 测试?

iqianxing 回复

这个回答做到了:
talk is cheap show me the code.
这套代码工具,可以解决读接口的比对问题,也是我文中所面对的问题。
当然我的Jmeter+Ant还是有其优势的:

  1. 接口测试请求链接数据不是数据库/文本等等已经保存好的,需要新创建测试数据。
  2. 请求和请求之间存在数据关联。即和上面第一种情况结合起来。

至少这两种情况,Jmeter还是比较方便的。
我不展开了,我相信python/node.js能做到。

zyanycall 回复

此外,进行接口串联,代码实现也比jmeter快与高效,周末有时间再分享

iqianxing 回复

有你分享的时间,我Jmeter都干完活了……行了大兄弟,别在我这掰扯这些了。
我文中写的那么多Jmeter的优点看来在你眼里都是P啊……“Jmeter,功能太丰富了,比如正则表达式,自定义变量,参数化,性能测试,定时执行等等。 这基本满足所有复杂的接口测试要求,自开发这些工具真的比不了。”
我期待你在github上的开源。

其实还可以用正则提取器因为json返回的格式都是有规则的,然后把提取的结果放入ArrayList 最后通过遍历提取出每个Key 然后进行对比,另外介绍个插件jmeter里有个插件jp@gc - JSON Format Post Processor 可以把格式化json接口返回的数据

iqianxing 回复

好的,谢谢你。我去看看

你好, 请问你对比的是新老接口的返回结果么? 如果是的话,为什么增加数据库的数据获取? 如果不是对比新老接口返回值,是对比返回结果和数据库中 预期返回结果的话,那么每一个接口虽然都是读,但是读的条件逻辑会不一样,那么数据准备这块也会很麻烦,怎么能一下子完成100多个呢?

dyy 回复

你好,是接口请求的内容保存在数据库里,所以才需要读数据库。
并不是接口返回的预期值保存在数据库中。

写个爬虫脚本,对新老两个接口进行爬虫,然后用python的对比函数处理结果,以前我就是这么干的😂

我最近也接到这样的测试了,还没不知道怎么弄

我数据量有百万。。需要取样来diff 新老接口的response 。 我用的是python 直接访问数据库,然后多线程执行diff

mark一下你的方法

仅楼主可见

👍 ,谢谢分享。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册