在测试金字塔模型中,从上至下分别是UI测试、接口测试、单元测试,UI测试的运行效率低,且维护成本高;而单元测试在研发测试活动中基本是由研发同学在负责;对于测试同学来说,接口自动化测试就成为了我们提高测试效率的重要手段之一。通过接口自动化测试,我们可以快速进行业务功能冒烟测试、回归测试等测试活动。
因此在项目研发测试过程中,各个测试团队都会特别重视自动化测试能力的建设。随着产品功能的不断迭代,自动化测试用例数量的不断增加,我们在执行自动化测试的过程中会发现自动化测试执行时失败的噪音会变大,排查自动化失败的用例会花掉我们大量的时间,而最终排查结果却显示只有一小部分用例失败是由于代码缺陷导致的,大部分的测试用例执行失败是测试环境或用例本身设计不合理导致的,接下来我们就谈谈治理接口自动化测试稳定性问题的一些常见思路。
测试环境稳定性治理
测试环境的稳定性是接口自动化测试用例可以持续稳定执行的第一要素,完备和稳定的测试环境对持续稳定地开展各项测试活动意义重大,我们可以从以下几个方面入手:
- 合理规划测试开发环境使用,这里我们仅讨论线下环境的dev和test环境,dev环境用于研发同学编码部署、自测、联调,以及基础的功能测试,部署研发分支代码;test环境用于测试同学执行手工测试、集成测试、自动化回归测试,部署master分支代码;
- 确保环境的使用权在可控范围内,测试环境的代码部署、配置变更、重启等操作权限应收口在测试owner手中,由测试owner进行维护;
- 规范变更流程,服务发布、参数配置、DDL/DML等变更应该有完善的发起/审核/执行/回滚流程,不能随意进行变更;
降低接口自动化测试用例对外依赖
很多时候我们发现接口自动化测试用例执行失败,是由于依赖服务不稳定导致,例如我们的被测应用A的接口内部,依赖应用B的某个接口,当我们在执行自动化测试用例时,可能会由于B应用服务的不稳定而导致A应用的接口自动化测试失败,甚至B应用服务的接口还会往下依赖C应用等,当我们的调用链路越长,自动化测试用例的稳定性就越差。
而降低自动化测试用例耦合性最好的方法就是通过mock组件,直接返回我们需要下游接口返回的结果,通过这种方式,我们不仅能降低对下游应用接口的依赖,还能更方便地进行一些异常场景的测试,例如超时异常或者一些不太容易构造的业务异常等场景。在单元测试或单接口测试中我们可以使用mockito等组件,而在跨微服务接口的测试场景中,我们可以通过在spring context中插入mock规则的方式,通过mock组件拦截返回我们需要的mock结果。
自动化测试用例中减少数据库连接的使用
接口自动化测试的断言和校验包括两部分:接口响应体和数据持久化。举个例子,我们的被测接口是注册用户,我们的测试步骤应该是:构造调用参数 -> 发起接口调用 -> 校验接口响应体 -> 校验数据库中的用户数据持久化。通常我们会封装一些DriverManager.getConnection()方法来实现自动化测试脚本对数据库的操作:连接数据库、查询数据,然后转换数据格式并进行数据完整性、正确性的校验。
当然,我们通过良好的代码规范,在数据库操作完后,在 finnally 模块中增加DriverManager.getConnection().createStatment().close()方法可以及时释放数据库连接,减缓数据库的压力。但是当我们并发地执行自动化测试用例时,不可避免地会建立大量的数据库连接,同时由于部分用例中查询的数据量过大,或者sql索引建立不规范等原因,会导致数据库连接被长时间占用,从而影响其他测试用例的执行,甚至影响手工测试执行。
那么如何规避上述问题呢,最简单直接且有效的方式,就是通过接口调用请求服务端的查询接口,通过查询接口返回的结果来判断。仍然以上面场景为例,我们的测试步骤就变为:构造调用参数 -> 发起接口调用 -> 校验接口响应体 -> 调用用户查询接口 -> 校验用户信息是否完整/正确。通过这也的方式,我们不仅能降低测试环境数据库的开销,提升测试环境稳定性,还能提升自动化测试用例的执行效率。
充分利用中间件测试方法
造成自动化测试用例运行不稳定的另一个场景,就是涉及到一些例如定时调度任务、异步消息等中间件的用例。例如测试环境异步任务5分钟或10分钟执行一次,那么我们就需要等到定时任务触发后,才能进行结果校验,这也无疑会大大降低我们自动化测试用例的执行效率和稳定性;同样地,针对异步消息的测试场景,我们大多数时候会依赖上游或者域内其他应用投递的异步消息,而我们想要在上游系统中去构造一个异步消息是较困难的,不仅依赖上游系统环境的稳定性,且还依赖对方功能的可靠性,当对方环境出现故障或功能有缺陷时,我们的自动化测试用例就会执行失败。
这时候我们应该把中间件提供的一些公共测试方法好好利用起来,针对调度任务的场景,我们可以获取到业务id,调用调度任务的执行接口,执行指定的某一条任务数据,这也既不会影响其他同学测试,也可以更快速高效地执行我们想要的动作;另外针对异步消息地场景,我们可以使用msgbroker中间件的消息mock能力,将我们需要的消息体构造出来后投递到我们需要的消息分组或指定的消息消费服务器上,如果担心消息乱序或者跑偏的情况,我们可以在做好消息幂等处理的前提下,进行消息重投,保证我们服务器可以接收到消息。