报名参加CloudWeGo黑客松,奖金直推双丰收! 了解详情
写点什么

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:4311044

评论

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

区块链食品安全追溯系统,区块链溯源优势

13530558032

直播选择 RTC 还是 RTMP?

anyRTC开发者

音视频 WebRTC CDN RTC RTMP

直播 | 如何使用Ranger增强权限管理?

LooK

大数据 数据分析 数据 Bigdata

聪明人的训练(十五)

Changing Lin

4月日更

无代码开发会是未来的趋势吗?

优秀

无代码

一文看懂Modbus协议

不脱发的程序猿

物联网 通信协议 智能硬件 4月日更 Modbus协议

一个单例还能写出花来吗?

艾小仙

Java 设计模式

面试官:Java中线程是按什么顺序执行的?

华为云开发者联盟

Java 线程 执行顺序 多线程并发

ConcurrentHashMap源码深度解析(一)(java8)不可不知的基本概念(助你拿下源码事半功倍)

徐同学呀

ConcurrentHashMap Java源码 JUC

python 实现类属性的懒加载装饰器

一代咩神

Python 懒加载 类属性 描述器

看了这篇MySQL,开发功力又升级

学Java关注我

Java 编程 程序员 架构 计算机

知乎载量破100W !阿里大佬的Java性能调优实战手册 一网打尽BAT大厂

比伯

Java 程序员 架构 面试

openLooKeng V1.2.0 发布

LooK

大数据 数据 Bigdata

Windows 下 搭建 Flutter 环境

U2647

flutter 4月日更

科技赋能快餐零售商突破瓶颈:英特尔AI技术助力汉堡王打造保护顾客隐私的订单推荐系统

E科讯

ConcurrentHashMap 源码深度解析(java7)原来如此简单(写的真好,建议收藏)

徐同学呀

ConcurrentHashMap Java源码 JUC

区块链电子合同一体化平台--破解信任难题

13530558032

数据虚拟化引擎openLooKeng介绍

LooK

大数据 数据分析 Bigdata

Python和Java的区别

Sakura

4月日更

混沌大佬系列第二期 - Jesse Robbins

混沌工程实践

混沌工程 混沌大佬 灾难大师 游戏日 GameDay

HDFS的动态扩容及动态缩容

五分钟学大数据

hadoop hdfs 4月日更

阿里P8大牛亲自教你!带你快速通过面试,Android岗

欢喜学安卓

android 程序员 面试 移动开发

一直做着行业最“新”的尝试:NA(Nirvana)Chain受邀出席共为·创新大会并办展

区块链第一资讯

ConcurrentHashMap源码深度解析(二)(java8)直呼Doug Lea是真的细(带你参透扩容机制)

徐同学呀

ConcurrentHashMap Java源码 JUC

编排包在设计与运行两态之间的运用价值体现

鲸品堂

服务编排 实践案例

portal 认证 - 下线流程

箭上有毒

4月日更

涨薪5K的Java虚拟机:垃圾回收,Serial GC,卡表你想学吗?

小Q

Java 学习 面试 JVM GC

iOS 面试策略之算法基础4-5节

iOSer

ios 面试 算法面经 算法解析

2021年5个最佳YouTube视频下载器

科技猫

软件 工具 网站 分享 下载youtube视频

Linux pwd 命令

一个大红包

Linux linux命令 4月日更

智慧平安社区整体解决方案,智慧安防小区建设

13530558032

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