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

简介:

集成测试的挑战

随着软件系统的复杂性逐渐增加,微服务、面向服务的架构(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查看结果:
可以看见刚才访问的两个地址都已经被记录,同时由于第二个地址增加了时间戳,所以原始对比结果认为他们是不相同的。


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


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










本文转自 小强测试帮 51CTO博客,原文链接:http://blog.51cto.com/xqtesting/2068569,如需转载请自行联系原作者
目录
相关文章
|
1月前
|
运维 Linux Apache
Puppet 作为一款强大的自动化运维工具,被广泛应用于配置管理领域。通过定义资源的状态和关系,Puppet 能够确保系统始终处于期望的配置状态。
Puppet 作为一款强大的自动化运维工具,被广泛应用于配置管理领域。通过定义资源的状态和关系,Puppet 能够确保系统始终处于期望的配置状态。
59 3
|
1月前
|
运维 Linux Apache
Puppet这一强大的自动化运维工具,涵盖其基本概念、安装配置及使用示例
【10月更文挑战第8天】本文介绍了Puppet这一强大的自动化运维工具,涵盖其基本概念、安装配置及使用示例。Puppet通过定义资源状态和关系,确保系统配置始终如一,支持高效管理基础设施。文章详细讲解了Puppet的安装步骤、配置方法及DSL语言示例,帮助读者快速掌握Puppet的使用技巧。
66 2
|
12天前
|
安全 前端开发 测试技术
如何选择合适的自动化安全测试工具
选择合适的自动化安全测试工具需考虑多个因素,包括项目需求、测试目标、系统类型和技术栈,工具的功能特性、市场评价、成本和许可,以及集成性、误报率、社区支持、易用性和安全性。综合评估这些因素,可确保所选工具满足项目需求和团队能力。
|
13天前
|
运维 Ubuntu 应用服务中间件
自动化运维工具Ansible的实战应用
【10月更文挑战第36天】在现代IT基础设施管理中,自动化运维已成为提升效率、减少人为错误的关键手段。本文通过介绍Ansible这一流行的自动化工具,旨在揭示其在简化日常运维任务中的实际应用价值。文章将围绕Ansible的核心概念、安装配置以及具体使用案例展开,帮助读者构建起自动化运维的初步认识,并激发对更深入内容的学习兴趣。
36 4
|
15天前
|
运维 监控 数据安全/隐私保护
自动化运维工具的设计与实现
【10月更文挑战第34天】在现代IT基础设施管理中,自动化运维工具扮演着至关重要的角色。它们不仅提高了运维效率,还确保了服务的连续性和稳定性。本文将深入探讨如何设计并实现一个自动化运维工具,从需求分析到功能实现,再到最终的测试与部署。我们将通过一个简单的代码示例来展示如何自动执行常见的运维任务,如日志清理和性能监控。文章旨在为读者提供一套完整的方法论,以便他们能够构建自己的自动化运维解决方案。
|
25天前
|
编解码 人工智能 自然语言处理
迈向多语言医疗大模型:大规模预训练语料、开源模型与全面基准测试
【10月更文挑战第23天】Oryx 是一种新型多模态架构,能够灵活处理各种分辨率的图像和视频数据,无需标准化。其核心创新包括任意分辨率编码和动态压缩器模块,适用于从微小图标到长时间视频的多种应用场景。Oryx 在长上下文检索和空间感知数据方面表现出色,并且已开源,为多模态研究提供了强大工具。然而,选择合适的分辨率和压缩率仍需谨慎,以平衡处理效率和识别精度。论文地址:https://www.nature.com/articles/s41467-024-52417-z
43 2
|
10天前
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
|
1月前
|
运维 关系型数据库 MySQL
自动化运维工具Ansible的实战应用
【10月更文挑战第9天】在现代IT运维领域,效率和可靠性是衡量一个系统是否健康的重要指标。自动化运维工具Ansible因其简洁、易用的特性,成为了众多企业和开发者的首选。本文将通过实际案例,展示如何利用Ansible进行日常的运维任务,包括配置管理、软件部署以及批量操作等,帮助读者深入理解Ansible的应用场景及其带来的效益。
|
1月前
|
人工智能 运维 监控
自动化运维:从脚本到工具的演变之路
【10月更文挑战第8天】在数字化时代的浪潮中,运维不再是简单的硬件维护,它已经演变成一场关于效率、稳定性和创新的技术革命。本文将带您领略自动化运维的魅力,从最初的脚本编写到现代复杂的自动化工具,我们将一探究竟,看看这些工具如何帮助运维人员简化日常任务,提升工作效率,并最终推动业务发展。
|
20天前
|
NoSQL 测试技术 Go
自动化测试在 Go 开源库中的应用与实践
本文介绍了 Go 语言的自动化测试及其在 `go mongox` 库中的实践。Go 语言通过 `testing` 库和 `go test` 命令提供了简洁高效的测试框架,支持单元测试、集成测试和基准测试。`go mongox` 库通过单元测试和集成测试确保与 MongoDB 交互的正确性和稳定性,使用 Docker Compose 快速搭建测试环境。文章还探讨了表驱动测试、覆盖率检查和 Mock 工具的使用,强调了自动化测试在开源库中的重要性。
下一篇
无影云桌面