AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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

评论

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

VLDB 2024 圆桌会议回顾:展望物联网与 AI 时代的时序数据库

Apache IoTDB

fetch --nohooks webrtc 失败

webrtc developer

2024中国算力大会,河南如何绘写算力长卷?

脑极体

AI

Mint Expedition Season 3 拉开帷幕:登顶高峰的时刻到了

NFT Research

blockchain web3 空投

关于深度学习量化的操作

芯动大师

深度学习 gpu 模型化

TikTok怎么开直播?TikTok直播专线是什么?

Ogcloud

海外直播专线 tiktok直播 tiktok直播专线 海外直播网络 tiktok直播网络

VLDB 2024 圆桌会议回顾:展望物联网与 AI 时代的时序数据库

Apache IoTDB

工业物联网PaaS平台的商业模式研究

不在线第一只蜗牛

云原生 物联网 PaaS

mac苹果电脑办公套件全家桶下载:Office2019 for Mac 下载

你的猪会飞吗

Microsoft Office 2019 office 2019 mac破解软件下载

万界星空科技MES系统:食品加工安全的实时监控与智能管理

万界星空科技

mes 万界星空科技 食品MES 食品行业 食品

四类取整方式

不在线第一只蜗牛

c++ C#

TikTok直播专线服务商推荐

Ogcloud

海外直播专线 tiktok直播 tiktok直播专线 tiktok直播网络 TikTok跨境直播

茶思屋直播|TinyEngine+AI:聚焦主航道,在实践中探索低代码技术黑土地

OpenTiny社区

低代码 OpenTiny TinyEngine

离散制造 vs 流程制造:锚定精准制造未来,从装配线到化学反应,实时数据集成在制造业案例中的多维应用

tapdata

数据库

试用完几十款ETL工具后的经验总结,ETL工具用这三款就足够了

RestCloud

kettle ETL DataX ETL数据集成

开发一个 PicGo 插件

yuanyxh

前端 PicGo js

TON基金会与Curve Finance合作:推出基于TON的新型稳定币互换项目

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 NFT开发 公链开发

干货满满!第二期流程挖掘实践训练营圆满落幕~

望繁信科技

流程挖掘 流程资产 流程智能 数字北极星 望繁信科技

解锁 PDF 文件:使用 JavaScript 和 Canvas 渲染 PDF 内容

yuanyxh

前端 js PDF

借助Python和搜狐视频联盟API自动推荐热门视频

幂简集成

视频 API

OpenAI o1开辟“慢思考”,国产AI早已集结在CoE“组团”先出发

脑极体

AI

火山引擎AI创新巡展深圳站定档9月24日!豆包大模型将全新发布视频生成模型

新消费日报

谷歌云推出全新区块链RPC服务:简化Web3开发

区块链软件开发推广运营

交易所开发 dapp开发 区块链开发 公链开发 代币开发

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