其他
开源 | AREX:携程新一代自动化回归测试工具的设计与实现
作者简介
haibing,携程研发能效经理和SRE,关注自动化测试,能效提升方向的工具技术。
探索中遇到的问题
以上的各种探索都达到了一定的效果,但还是存在两个问题:
1)自动化测试侧重于自动化执行,维护工作依旧是“手工”,产出比不是很乐观。
2) 在需要构造大量测试数据、写场景、回归测试范围大、发布频繁的场景下,不管是手工测试还是自动化测试,开发测试都还是面临着巨大的工作量,包括用例和数据的维护工作,测试的痛点并没有有效解决。
新的建设目标
因此,研发团队给我们提了新的建设目标:“质量要提升,要保证。费电可以,但不能废人。”
录制:不只是录制生产的请求,也录制请求处理过程中涉及到的数据。 回放:不只是回放请求, 也把涉及的数据MOCK到应用里边。 比对:用录制回放的差异比对来代替测试断言。
3.1 什么是AREX
AREX回归测试逻辑
AREX 回归测试的实现逻辑是通过在生产环境录制接近全量的业务场景请求和数据,然后在测试环境回放这些真实的请求和数据,对新版本的应用进行全面、快速的回归测试。
目标场景
需要频繁大量造数据的测试场景;
需要大量业务需要回归测试的场景;
测试人力资源欠缺的开发场景;
频繁发布,频繁回归测试的场景;
接下来从工作流程的角度,来讲解AREX是如何工作的。
下图是没有接入AREX的应用的调用链。
4.1 AREX gent录制回放原理
以下通过一个简单的函数,说明AREX Agent的录制回放原理:
4.2 AREX技术挑战
AREX AGENT技术栈
由于性能好、且代码更容易阅读、容易理解,我们采用了ByteBuddy 库实现字节码修改。
解决调用链丢失
以上是 AREX TRACING 传递实现中比较普遍的基础场景。除此以外,我们的应用中还有大量使用多线程、异步等技术的场景,这种场景下调用链会丢失,给数据的串联带来很大的困难。
为了解决调用链丢失的问题,我们实现了 Runnable,Callable,ForkJoinTask,Async Client 这些类的封装。
实现录制和回放注入
以下是一个实现录制回放的代码实例。
@Override
public List<MethodInstrumentation> methodAdvices() {
ElementMatcher<MethodDescription> matcher = named("doFilter")
.and(takesArgument(0, named("javax.servlet.ServletRequest")))
.and(takesArgument(1, named("javax.servlet.ServletResponse")));
return Collections.singletonList(new MethodInstrumentation(matcher, FilterAdvice.class.getName()));
}
模块(ModuleInstrumentation: FilterModuleInstrumentationV3):逻辑管理的概念,是将多个注入类、或者封装类,放到一个模块中。 类型(TypeInstrumentation: FilterInstrumentationV3):就是我们要定位到注入对象的类,即被注入的应用类。 函数(MethodInstrumentation):此函数要定位到注入修改的函数。
如果 MOCK 结果符合条件,则返回 MOCK 数据; 如果当前状态是录制中,则将查询 SQL+ 查询结果原始数据保存到 AREX 的数据库。
实现版本管理
流行的组件往往存在多个版本同时在不同的系统中使用,不同的版本实现方式差别可能很大,甚至不兼容。
针对这种问题,AREX 做到了多个版本的兼容。在应用启动的时候,AREX Agent 会捕获到所有的依赖包的信息,比如 JAR 包的 Manifest.MF 文件,从 Manifest 中获取类库的版本信息,然后根据版本信息来启动对应的 AREX 注入代码,由此实现实现了多个版本的兼容。
如下图所示,设置了当前注入脚本适配的版本范围,这样 AREX 就可以在这些类加载前识别出应用依赖的组件版本,之后在类加载时进行版本的匹配,保证正确的代码注入。
实现代码隔离
由于 AREX 大多数的使用场景是在生产环境进行录制,在测试环境进行回放,因此稳定性至关重要。为了系统的稳定性,防止 Agent 的代码影响到被测应用的代码执行,AREX 实现了代码隔离互通。
AREX核心JAR是在一个独立的ClassLoader中加载,和用户的应用代码不互通。为了保证注入的代码可以在运行时被正确访问,对 ClassLoader进行了简单的修饰,如下图所示。
解决时间问题
携程的很多业务场景是时间敏感的,经常会遇到录制的时间在回放的时候已经过期了,业务逻辑走不下去,导致回放失败的情况。
我们用自己实现的 currentTimeMillis() 代理了 Java 原有的 currentTimeMillis() 调用,时间的记录和回放都将按照录制当时的场景来执行,从而实现了时间的 Mock。
在AREX Agent #182 针对此场景进行了详细的描述:
解决缓存问题
实际应用中会使用各式缓存来提升运行时的性能,由于缓存数据的差异导致的执行结果不一致,在录制回放里边是一个很大的问题。
AREX 提供了动态类 Mock 的功能,实现方法是将访问本地缓存的方法配置成动态类,相当于你自定义了这个方法进行 Mock,会在生产环境录制你配置的这个动态类方法的数据,回放相应的匹配出数据返回。
缓存配置容易忽略,对回放通过率有很大影响; 每个应用都有自己的缓存实现,无法提前处理,需要人工参与,有配置成本。
4.3 AREX其他优势
支持写接口测试
要验证系统修改后的业务正确性,仅校验返回结果是远远不够的,通常还需要验证中间过程数据的正确性,例如业务系统写数据库的数据内容是否正确等等。
针对这一点,AREX 在写接口测试也做了完美支持。
AREX 在录制和回放的过程中会记录下新旧版本系统对外的数据库请求,并将这两个请求进行比对,如果存在差异则会在回放报告中进行展示
由于 AREX MOCK 了所有对第三方依赖的请求,支持数据库、消息队列、Redis 数据的验证,甚至支持验证运行时的内存数据,并且在回放的过程中不会真的产生对数据库的调用,因此不会产生脏数据。
生产问题快速定位
在实际使用过程中,AREX 还可以用来实现生产问题的快速定位。
生产问题出现后因版本差异、数据差异等问题,导致开发人员难以在本地复现,进行 Debug 的成本很高,很费事费力。
利用 AREX,可以强制在生产环境录制有问题的 Case(应答报文中会生成唯一的 Record ID),随后启动本地开发环境,发送请求的报文头添加此 Record ID,就可以在本地复原录制到的请求和数据,随后利用本地代码直接 Debug 生产问题。
五、AREX自动化测试的实施与展望
技术重构项目,特别是请求应答不修改的场景。这种使用场景下,几乎不需要测试人员参与,开发人员自己就可以通过 AREX 进行快速自测,保证质量。 开发人员提升自测质量。
5.2 AREX优化
初期AREX在携程内部试用阶段,大家对工具的评价还是很好的。但是,在扩大使用范围、特别是在有其他团队非主动接入时,就出现了各种问题:
误报率高(时间、uuid、序列号等等),前期比对过滤配置多。
代码变更的预期确认很麻烦,人工干预量大。
目前我们正在对AREX配置和比对能力进行重点优化。
配置增强
现阶段要保证高比对通过率需要大量的人工干预(比对忽略配置等),所以首先要做的就是降低用户配置成本:
可视化直观展示差异点
人工标记操作提升易用性
配置更新可重算和重新执行
同类聚合
通过聚合的方式将同类的错误进行多维度聚合,方便开发人员观察差异。最终达到大部分情况下,开发只要确认一个差异就可以去掉大部分的比对差异的效果
算法降噪
1)预分析降噪
预分析降噪是将录制流量的生产版本发布到测试环境,对此版本进行回放并比对其差异,提前识别出类似于 token,序列号等的“噪声”点。
之后将噪声标记到规则库,作为知识库。
最后识别报文和数据的 Schema 变更,进行主动降噪,减少用户手工配置的成本。
精准测试
精准测试是为了缩小测试范围,后续AREX中也会引入精准测试,主要目的是做到明确比对差异的来源。
我们计划将代码变更、代码执行链路与AREX的回放关联起来,通过代码变更与差异结果的双向追溯,让用户“可观察”地确认问题。首先识别差异是否是由代码更新导致的预期中的差异,进一步主动过滤识别非预期问题的差异点。
经过对比对差异结果的优化处理,可以有效地降低研发配置成本、提升差异结果的精确度,这才是AREX的自动化回归测试真正可以落地的价值所在。
六、写在最后
AREX经过不断优化,逐步达到了用真实流量和数据进行回归测试的目标,降低了成本,提高了质量,达到了建设初期设定的目标。
当然还有很多需要优化和提升的地方,包括算法、性能、支持范围等等,需要进一步的优化发展。也希望各位有志之士可以加入到我们AREX开源项目的共建当中。
应用SQL性能风险识别与预警,携程金融支付AppTrace落地实践
携程是如何在测试时做精准流量筛选的 携程APP/Web功能和视觉测试平台-Watcher 基于 BDD 理念的 UI 自动化测试在携程度假的应用
“携程技术”公众号
分享,交流,成长