10 月 23 - 25 日,QCon 上海站即将召开,现在购票,享9折优惠 了解详情
写点什么

Diffy:Twitter 的开源自动化测试工具

  • 2015-10-28
  • 本文字数:4001 字

    阅读完需:约 13 分钟

集成测试的挑战

随着软件系统的复杂性逐渐增加,微服务、面向服务的架构(Service-oriented architectures, SOA)等概念,越来越多的被应用到系统的设计当中,一同伴随的结果就是系统组件逐渐增加。

对于测试活动而言,最底层的单元测试,主要测试目标是单一的功能模块。它能够确保每个组件自身业务逻辑的正确性,但是随着系统组件依赖的增加,对单一模块的单元测试难度和成本都会上升。同时,单元测试覆盖率的提升,只能确保系统各个组件的正确性,组件之间的集成测试仍然是必不可少的。

传统集成测试的难点在于,对于每一个模块,都会有几个需要测试覆盖的分支,随着模块的增加,这些测试分支的组合,将会呈现几何级的增长(如图 1 所示)。

图 1:随着模块增加,测试复杂度指数级增加

Twitter 公司发布的自动化测试工具 Diffy ,就是为了降低开发人员对这种复杂系统的测试成本。

Diffy 简介

Diffy 是一个开源的自动化测试工具,它能够自动检测基于 Apache Thrift 或者基于 HTTP 的服务。使用 Diffy,只需要进行简单的配置,之后不需要再编写测试代码。

Diffy 主要基于稳定版本和它的副本的输出,对候选版本的输出进行比较,以检查候选版本是否正确。因此,Diffy 首先假设候选版本应该和稳定版本有“相似”的输出。即不论候选版本和稳定版本系统模块是否相同,他们的最终输出应该是“相似”的。

这里一直使用“相似”,而不是使用相同,这是因为相同请求可能会有一些 Diffy 不需要关心的干扰。比如:

  • 响应中包含服务器生成的时间戳
  • 代码中使用了随机数
  • 系统服务间有条件竞争

Diffy 有自己的噪声清理方式,确保这些噪声不会影响最终的结果。

Diffy 工作原理

在测试过程中,Diffy 充当一个代理,它能够将来源请求分发到不同版本的系统中去,通过对各个版本系统的输出进行对比,做出最终的结论。

Diffy 需要三个版本的系统,以实现它的噪声过滤和对比功能,它们分别是:

  1. 候选版本:该版本是待测版本,相对于生产环境版本有着跟新的代码
  2. 稳定版本:该版本通常是已经上线版本,或者是已知功能正常的版本
  3. 稳定版本副本:该版本是稳定版本的副本,和稳定版本运行相同的代码,主要用于排除噪声

整个运行流程为:

其中:

  • 原始区别为候选版本和稳定版本之间输出的区别,其中可能会包含上述的噪声
  • 噪声从稳定版本和其副本中获得,如果两个运行相同代码的系统输入相同输出却不同,则 Diffy 会认为这是开发人员不需要关心的噪声。

基于上述两个区别集合,Diffy 可以识别出候选版本和稳定版本真实的区别,这些区别很有可能就是一个缺陷。

当然,对于一个概率性出现随机值,仅仅一次请求的结论可能是不准确的。例如对于一个 50% 概率出现 true 或者 false 的布尔值,则有 50% 的概率会出现候选版本和稳定版本的不同,同时又会有 50% 的概率出现稳定版本和其副本出现不同(即将这个值认定为噪声),最终会有 25% 的概率认为这是一个缺陷。因为此时稳定版本和其副本值相同,候选版本和稳定版本值不同。因此,Diffy 还会聚合原始区别和噪声,当发现二者出现的概率类似的时候,会认定之前识别出来的缺陷属于误报。

示例

最后,通过 Diffy 仓库中的示例,来大致了解下 Diffy 的运行方式和过程:

步骤 1:克隆源码,并进行构建:

复制代码
git clone https://github.com/twitter/diffy.git
cd diffy
./sbt assembly

国内如果下载速度很慢,可以修改下 sbt 的镜像,使用国内的镜像:

复制代码
#cat ~/.sbt/repositories
[repositories]
local
osc: http://maven.oschina.net/content/groups/public/
oschina-ivy:http://maven.oschina.net/content/groups/public/,
[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/
[type]s/[artifact](-[classifier]).[ext]
sonatype-oss-releases
maven-central
sonatype-oss-snapshots

步骤 2:启动候选服务。这里直接使用 example.sh,因此对应的候选服务地址为:http-candidate.herokuapp.com:80

步骤 3:启动基准服务(稳定版本)。这里直接使用 example.sh,因此对应的候选服务地址为:http-primary.herokuapp.com:80

步骤 4:启动稳定版本副本。这里对应的是:http-secondary.herokuapp.com:80

步骤 5:使用以下命令运行 Diffy(example.sh):

复制代码
java -jar diffy-server.jar \
-candidate='http-candidate.herokuapp.com:80' \
-master.primary='http-primary.herokuapp.com:80' \
-master.secondary='http-secondary.herokuapp.com:80' \
-service.protocol='http' \
-serviceName='My Service' \
-proxy.port=:8880 \
-admin.port=:8881 \
-http.port=:8888 \
-rootUrl='localhost:8888'

该命令指定了 Diffy 需要的三个版本对应的访问地址,同时在 8880 端口开启代理,8888 端口开启了结果访问服务。现在可以通过访问 8880 端口,Diffy 会将请求同时分发到三个版本的 http 服务上,然后记录这三个 http 服务的返回值。通过访问 8888 端口,就可以看见对这三个返回内容的对比结果。命令执行输出如下:

复制代码
coolex scala-2.11 # java -jar diffy-server.jar \
> -candidate='http-candidate.herokuapp.com:80' \
> -master.primary='http-primary.herokuapp.com:80' \
> -master.secondary='http-secondary.herokuapp.com:80' \
> -service.protocol='http' \
> -serviceName='My Service' \
> -proxy.port=:8880 \
> -admin.port=:8881 \
> -http.port=:8888 \
> -rootUrl='localhost:8888'
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
I 0908 13:09:41.130 THREAD1: HttpMuxer[/admin/metrics.json]
= com.twitter.finagle.stats.MetricsExporter(<function1>)
I 0908 13:09:41.189 THREAD1: HttpMuxer[/admin/per_host_metrics.json]
= com.twitter.finagle.stats.HostMetricsExporter(<function1>)
I 0908 13:09:41.393 THREAD1: /admin
=> com.twitter.server.handler.SummaryHandler
I 0908 13:09:41.394 THREAD1: /admin/server_info
=> com.twitter.finagle.Filter$$anon$2
I 0908 13:09:41.394 THREAD1: /admin/contention
=> com.twitter.finagle.Filter$$anon$2
I 0908 13:09:41.394 THREAD1: /admin/threads => com.twitter.server.handler.ThreadsHandler
I 0908 13:09:41.394 THREAD1: /admin/threads.json
=> com.twitter.server.handler.ThreadsHandler
I 0908 13:09:41.394 THREAD1: /admin/announcer
=> com.twitter.finagle.Filter$$anon$2
I 0908 13:09:41.395 THREAD1: /admin/dtab
=> com.twitter.finagle.Filter$$anon$2
I 0908 13:09:41.395 THREAD1: /admin/pprof/heap
=> com.twitter.server.handler.HeapResourceHandler
I 0908 13:09:41.395 THREAD1: /admin/pprof/profile
=> com.twitter.server.handler.ProfileResourceHandler
I 0908 13:09:41.395 THREAD1: /admin/pprof/contention
=> com.twitter.server.handler.ProfileResourceHandler
I 0908 13:09:41.395 THREAD1: /admin/ping
=> com.twitter.server.handler.ReplyHandler
I 0908 13:09:41.396 THREAD1: /admin/shutdown
=> com.twitter.server.handler.ShutdownHandler
I 0908 13:09:41.396 THREAD1: /admin/tracing
=> com.twitter.server.handler.TracingHandler
I 0908 13:09:41.396 THREAD1: /admin/events
=> com.twitter.server.handler.EventsHandler
I 0908 13:09:41.396 THREAD1: /admin/logging
=> com.twitter.server.handler.LoggingHandler
I 0908 13:09:41.397 THREAD1: /admin/metrics
=> com.twitter.server.handler.MetricQueryHandler
I 0908 13:09:41.397 THREAD1: /admin/clients/
=> com.twitter.server.handler.ClientRegistryHandler
I 0908 13:09:41.397 THREAD1: /admin/servers/
=> com.twitter.server.handler.ServerRegistryHandler
I 0908 13:09:41.397 THREAD1: /admin/files/
=> com.twitter.server.handler.ResourceHandler
I 0908 13:09:41.397 THREAD1: /admin/registry.json
=> com.twitter.server.handler.RegistryHandler
I 0908 13:09:41.403 THREAD1: Serving admin http on 0.0.0.0/0.0.0.0:8881
I 0908 13:09:41.478 THREAD1: Finagle version 6.28.0
(rev=de123b8f9d074c4e345ebd67e1a0e870bb921544) built at 20150827-162434
I 0908 13:09:43.010 THREAD1: networkaddress.cache.ttl
is not set, DNS cache refresh turned off
I 0908 13:09:43.507 THREAD1: Tracer:
com.twitter.finagle.zipkin.thrift.SamplingTracer
I 0908 13:09:43.810 THREAD1: zipkin-tracer
resolved to Addr.Bound, current size=1
I 0908 13:09:43.811 THREAD1: candidate resolved to Addr.Bound, current size=1
I 0908 13:09:43.811 THREAD1: primary resolved to Addr.Bound, current size=1
I 0908 13:09:43.811 THREAD1: secondary resolved to Addr.Bound, current size=1
I 0908 13:09:43.885 THREAD1: Scheduling com.twitter.diffy.workflow.
FunctionalReport at 2015-09-08 13:09:43 +0000

步骤 6:发送一些请求,让 Diffy 来记录和分析:

复制代码
curl localhost:8880/json
curl localhost:8880

步骤 7:通过 localhost:8888 查看结果:
可以看见刚才访问的两个地址都已经被记录,同时由于第二个地址增加了时间戳,所以原始对比结果认为他们是不相同的。

(点击放大图像)

点击对比失败的地方,可以展示出两次对比不同之处:

(点击放大图像)

可以看见,该请求两个版本的不同是由时间戳导致的。如果选择“排除噪声”,那么最终结论会变成相同。

(点击放大图像)


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-10-28 18:4311346

评论

发布
暂无评论
发现更多内容

Android模拟面试,解锁大厂—,这些面试题你会吗

android 程序员 移动开发

Android知识笔记:记录 2 个 “容易误解,网易的朋友给我这份339页的Android面经

android 程序员 移动开发

Android开源:想送你一款小清新的加载等待 控件,源码+原理+手写框架

android 程序员 移动开发

Android强行进阶:自定义TabLayout,看似复杂的神器效果

android 程序员 移动开发

Android技能树 — Activity小结,【深夜思考

android 程序员 移动开发

Android插件化-Service篇,flutter通知推送

android 程序员 移动开发

自动驾驶汽车如何工作? 易筋 ARTS 打卡 Week 74

John(易筋)

ARTS 打卡计划

Android架构设计——MVC,flutterrow居中

android 程序员 移动开发

Android异步消息处理机制详解及源码分析,Android多线程实现方式及并发与同步

android 程序员 移动开发

Android知识笔记:记录 2 个 “容易误解(1),【干货】

android 程序员 移动开发

Android性能优化:这是一份全面&详细的内存优化指南,Flutter最新开源框架

android 程序员 移动开发

Android春招面经分享:一个Android渣渣终于拿到了一个offer

android 程序员 移动开发

Android热修复基础篇(二),android设计模式面试题

android 程序员 移动开发

Android开发:自定义TabLayout,神奇效果竟是如此简单,Android面试题集2021版

android 程序员 移动开发

Android开发:通过 webview 将网页打包成安卓应用,kotlin编程实践pdf

android 程序员 移动开发

Android文件系统总结——从-Android-Q-,面试必备知识点

android 程序员 移动开发

Android开源的精美日历控件,热插拔设计的万能自定义UI

android 程序员 移动开发

Android性能优化之启动速度优化,Android面试资料集合

android 程序员 移动开发

Android数据库的使用(增删改查),移动开发工程师

android 程序员 移动开发

Android架构之LiveData组件,原理竟然是这

android 程序员 移动开发

Android热修复基础篇(一),flutter图片压缩

android 程序员 移动开发

Android架构组件JetPack之Room(三),Android大厂74道高级面试合集

android 程序员 移动开发

Android源码解析——Handler,看完直接跪服

android 程序员 移动开发

Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)

android 程序员 移动开发

Android源码-一文带你搞懂OkHttp,kotlin高阶函数

android 程序员 移动开发

Android开发:老板说要加点功能---我:相机变美团,程序员真的是吃青春饭吗

android 程序员 移动开发

Android快速开发工具集合——YUtils,webrtc音视频开发

android 程序员 移动开发

Android性能优化 _ 大图做帧动画卡?优化帧动画之 SurfaceView滑动窗口式帧复用

android 程序员 移动开发

Android性能优化之内存优化,android最新开发语言

android 程序员 移动开发

Android性能优化之启动加速35%,算法+分布式+微服务

android 程序员 移动开发

Android插件化主流框架和实现原理,一举拿下腾讯美团滴滴offer

android 程序员 移动开发

Diffy:Twitter的开源自动化测试工具_语言 & 开发_金灵杰_InfoQ精选文章