RPC服务测试新思路
作者|申言方
为了保证RPC服务的稳定,最大可能的防止BUG带到线上,测试过程中对RPC服务做接口测试是必要的步骤。目前的通用做法是在测试框架中引入被测服务的contract 包,再基于contract包开发对应的接口测试代码,并尽量全面的构建覆盖多个场景的入参。
目前的方式有几方面不足:
必须有一定Java基础的测试同学才能够胜任;
并且日常还需要频繁的维护测试代码以适应RPC接口的变更;
如果接口返回大量信息的话,并不能快速的判断结果的正确性;
在紧张的迭代排期下,很多时候只能对核心的RPC服务做接口测试,不能普及到所有的RPC服务。
鉴于目前的情况,那么有没有一种可以快速判断接口的正确性,同时又不用太多的人工干预的解决方案呢?
思路如果有一个解决方案,能够自动的获取入参,还能执行RPC服务接口的调用,并且可以准确判断接口返回的正确性,不就可以了?!RPC接口diff的构想开始形成,为了自动完成接口diff功能,那么就需要考虑一系列的问题:调用接口的入参从哪里获得、怎么从txt中把一长串字符串转成Java中的不同对象、测试代码的生成、怎么保证相同的参数同时调用不同机器上的不同代码、返回结果的对比等等。针对以上问题,小组成员集思广益,反复推敲方案,最终问题被各个击破,现把主要的几个问题的解决思路分享出来。
参数的来源:
转转测试部对整个测试环境做了分割,线下环境和沙箱环境数据是不通的,并且线下环境和沙箱上的数据量也不大,没有实际的分析价值;最终决定使用线上的数据,通过在RPC服务中添加拦截器,在执行具体的调用之前把入参以JSON格式输出到日志中, 随后通过公司的大数据平台,定时的启动处理日志的任务,从中分析出调用量最大的前50个接口的入参,接下来放到ftp上,这样就可以让后续的服务从ftp上获取。因为入参数据是从线上来的,所以调用沙箱和线上的接口,当代码的逻辑是一样的时候,理论上是会返回同样的结果,为后续的接口diff提供可能。
字符串转为Java对象:
既然JavaBean可以转换为JSON格式的字符串,同样的符合JSON格式的字符串也应该可以逆向转为对应的JavaBean。从ftp上获取的文件的内容已经是接口的入参转成的JSON格式的字符串,那么就可以逆向的复现调用这个接口的入参,并且是符合这个接口的参数列表的。
测试代码的生成:
借鉴Velocity的思想,提前准备一个模版文件,在实际的使用中,替换不同的字符,那么应该就可以生成一个内容为java代码的文件。
同时调用不同机器上的服务:
结合之前的分享《测试环境rpcclient动态调用RPC服务实践》,就可以实现相同的入参同时分别调用已上线的代码和本次修改的代码。
返回结果的对比:
返回的结果是不可知的,有可能是基本类型,有可能是一个集合类型,也有可能是就是个java对象,把它们转成统一的格式才能够无感的对比结果,这个时候JSON又可以大显身手,根据方案的需要,JSONDiffUtil工具类就应运而生,具体的对比细节不再详述。
同时为了满足测试工作对尽量减少人工干预,尽量全自动的实现所有步骤这一初衷,测试代码的生成和编译,以及运行后的对比和结果的记录都需要自动的完成,中间也是趟过了好多坑,不过好在已经几乎满足所有要求,接下来看一下大致的实现。
实现RPC diff框架流程图:
contract IBreadService服务示意代码:
大致步骤讲解:
需要提供一个类似如下内容的cases文件,提前告知我们需要接入的服务,这样可以在公司的大数据分析平台上,增加必要的任务,就可以自动的生成符合要求的数据;
createBreadTask:[{"key":"CreateBreadTaskParams","value":{"size":"6","number":99,”shape”:”xiyangyang”,”deadline”:” 1553415235000”}}]
“:”号前为接口名,后续部分为该接口的入参
从gitlab上下载分支后,解析所有符合规则的Service源文件,主要是为了获得该Service的imports信息,这样就拿到了该Service所提供接口的外部依赖的全集;
编译contract源码为contract.jar后,分析该contract.jar,通过Java Class的方法可以获得接口的参数列表;
通过第2、3步已经拿到被测RPC服务所有对外暴露接口的详细信息,再逐行解析步骤1中已经准备的cases文件,通过接口名和参数列表匹配出符合条件的接口,接下来替换模版文件中的指定位置的字符串后,就针对cases文件中的每一行对应的生成了一个.java源文件;
编译所有的测试代码源文件后,自动扫描所有.class文件,生成testng.xml文件;
运行TestNG,执行过程中,结合之前的分享《测试环境rpcclient动态调用RPC服务实践》,只需要给定服务器的IP就可以动态生成包含该机器上部署的所有服务的rpc.config;
通过查询接口从数据库中获取该任务的执行结果,还有该任务包含的接口的结果信息。
生成的示例代码(调用服务接口):
因为所有的步骤都是由代码完成的,对接入的RPC服务没有额外的特殊要求,理论上可以适用于所有的RPC服务。并且只要提供git分支链接和一个case文件,中间不需要在人工干预,速度也可以保证。cases中的内容来源于实际的线上环境或者线下测试过程中的有实际意义的日志,不掺杂人为的倾向,覆盖的场景也会更广,尤其适用于核心流程回归测试和需要大量入参来评估效果的情况。
在日常的使用过程中,针对不同的场景,运行指定的接口这一需求变得越来越强烈,针对这一情况,策略配置功能适时的推了出来。策略中配置不同的接口、结果接收人、RPC服务的git地址等必要信息,便可以对策略中的接口进行diff,同时也便于以后定时执行。
主要代码:
扫描contract
扫描cases文件并生成测试类源文件
结合具体场景说明:
广告召回补足策略需要尽快上线,已知情况
线下环境商品数量很少,并且类别不全,因此无法准确的评估策略的效果;
如果ABTest,只能通过其他指标来判断效果,容易有误差;
沙箱测试的话,需要考虑到线上商品的个数是动态变更的,如果先调用线上的服务,再调用沙箱上的服务,不能保证结果一定是策略的更新引起的。这个时候最好的测试方法就是RPC Diff。
所需步骤:
分析线上一个小时的服务日志,从中清洗出接口名和入参;
创建一个RPC Diff任务;
等待任务执行完成,查看线上稳定代码的返回结果和沙箱新代码的返回结果;
在对比大量结果的情况下,评估策略是否有效。
使用了新的测试方案,不需要再开发测试代码,同时也不需要在构造大量的测试数据,保证了需求可以提前上线。
监听beetle部署成功的MQ消息,可以自动的触发任务的执行,进一步的减少人工干预。
创建任务时,指定不同的测试类生成模版,可以实现结果diff、RPC接口测试等不不同场景的需要。
往期精彩回顾