NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

持续集成之“测试三角形与分段构建策略原则”

  • 2011-02-17
  • 本文字数:3396 字

    阅读完需:约 11 分钟

随着软件产品新特性的不断增加,软件自动化测试用例的数量也会成倍增长。对于一些历史“悠久”的遗留系统来说,甚至会积累数以万计的自动化测试用例。如果对这样的系统进行持续集成,还要求每个开发人员都要进行本地验证的话,困难的确不小。让我们还是看看 Joe 的团队是如何解决类似问题的吧。

在《戏说Checkin Dance 》一文 中,咱们说到:Joe? 的团队实施了带有令牌的持续集成提交流程纪律。由于每个人都做本地构建进行验证后再提交,所以持续集成平台上的构建结果比较稳定,每天持续集成服务器上的构建最多只有 一两次失败(常见的原因是忘记提交某个文件而导致失败,和因本地环境配置与平台环境配置不一致而导致失败),但一般都能在30 分钟内修复。随着项目的进 行,新功能不断地增加,自动化测试用例也越积越多。由于不做任何修改,本地构建脚本就会运行所有自动化测试用例,所以本地构建的运行时间也越来越长。团队里有人开始抱怨,“每次提交代码前,运行本地构建都超过15 分钟,这样太浪费时间。我们可否把那些不太重要的测试拿出去,不再运行了?”

一、自动化测试黄金三角形

作为团队的技术负责人,Joe 把大家叫到一起,就这个问题进行了专门的讨论。

“我们不能放弃运行这些测试。”Alice 说道,“在我前一个项目中,我们就是这么做的,结果,这些花精力写的测试都作废了。”

“那是为什么呢?”?Bob 问道。

Alice 回答道:“因为并不经常运行这些测试,随着功能的修改,有些测试的逻辑就不再是正确的了。而当再次运行发现这类问题时,通常的结果就是把这个测试删掉,因为修复这个测试的工作量太大了。”

“那持续运行所有测试的话,等待的时间太长了,也是一种浪费呀。?”Bob 说道。

此时,作为团队技术负责人的 Joe 说话了。“让我们先分析一下,到底有哪些什么原因让我们的测试在这么短的时间里就变成需要这么长时间了呢?”

“功能增加的多了,测试自然就多了呗。”

“功能增加了,自动化测试数据的准备工作也多了,需要的时间当然就长了。”

“现在我们的测试中有很多地方需要测试在原地等待结果返回,所以等待时间也挺长的。”

“大家还有没有其它原因?”Joe 追问道。

大家沉默了一会儿,Bob 说道:“好象主要就这些原因吧”。

“那好吧。功能多而导致测试多这是好事儿,说明我们大家都非常重视我们的自动化测试。对于‘测试准备时间变长’这个问题可以理解,因为我们的产品越来越复杂了。对于‘结果返回的等待问题‘嘛,需要具体问题,具体分析。前几天,我看到一个‘测试黄金三角形’,讲的就是自动化测试中各类测试的应具有的比例关系,对我很有启发。我在白板上画一下吧。”于是,Joe 走到白板前,将这个测试黄金三角形画了下来,如图 1 所示。

然后,Joe 将这个图形解释了一下。原来,这个三角形讲的就是单元测试、集成测试和验收测试的关系。首先,左边向上的箭头表示,越高层次的测试维护成本越高,运行时间越长。因此,对于单个测试来说,单元测试运行最快,维护最容易,而集成测试次之,验收测试则最高。? 每类测试的面积代表着该测试的数量。现在,业界有很多种工具支持单元测试,因此它的编写及维护成本相对其它两种测试来说较低,应使用单元测试对代码做尽可能多的测试覆盖。一般来说,单元测试覆盖率达到70~80%是比较理想的状态。

接着,Joe 问了大家一个问题:“我们产品中的这些自动化测试属于哪一类测试?”

Alice 说道:“那要看你怎么定义单元测试中的这个单元。”

“根据 WikiPedia 上的定义,一个单元是指应用程序中最小可测试的部分。既然我们使用面向对象的开发语言 C++,那么单元测试的粒度应该是类中的一个方法吧。而且,通常来说,如果一个测试包括以下任何一个情形,它就不是一个单元测试:(1) 需要连接数据库;(2) 需要网络通信;(3) 需要与文件系统打交道;(4) 不能和其它单元测试同时运行;(5) 需要对环境进行一些配置(如编辑配置文件)才能运行它。”Joe 回答道。

“要是这么说的话,我们的测试中,一部分是模块集成测试,一部分是验收测试,只有一小部分算是单元测试。我们的测试集合正好是一个倒三角。”Bob 边说,边在白板上画了出来,如图 2 所示。

“既然高层次上的测试(集成测试和验收测试)维护量比较大,今后我们应该加入更多的低层次测试(单元测试),对于关键功能进行集成测试和验收测试。如果对于测试用例具有等价性的话,我们应该用低层次测试来实现。这样我们就会达到自动化测试的黄金三角状态啦。”Joe 边说边在白板上笔划着,如图 3 所示。

“我同意你说法,但是仍旧没有解决我们目前遇到的问题。如何解决我们现在本地构建时间太长的问题呢?”Alice 有点儿不耐烦地问道。

二、分阶段构建?

“这还不容易, Martin Folwer (敏捷宣言的创造者之一) 已经给出了一个解决方案,那就是两阶段构建(Secondary Build)。也就是说,我们可以把那些运行比较慢,时间比较长且基本上不会失败的自动化测试用例挑选出来,组成一个新的测试集,在第二阶段运行,可以叫做‘二级构建阶段’。剩余的测试集仍旧放在第一个阶段运行,我们可以把第一个阶段叫做‘提交构建阶段’。”Joe 回答道。

“那什么时间运行这两个阶段的构建呢?”Bob 问道。

“提交阶段构建当然就是在我们每个人提交之后就运行啦。而且在我们提交之前,作为本地验证集合,在我们开发环境上也要运行同样的提交构建。一般来说,本地构建和提交构建最好都在五分钟内完成,最长也不要超过十分钟,否则开发人员就不愿意花时间做频繁地代码提交啦。另外,一旦提交阶段构建成功以后,就马上自动触 发第二阶段构建。而我们开发人员在持续集成服务器上的提交阶段构建成功以后,就可以继续进行其它的工作啦。”Joe 说道,“我们原来的六步提交图就变成这 个样子了。”说着,Joe 拿起白板笔就画了出来,如图4 所示。

“不对,这里有问题!持续集成强调尽早反馈。如果把测试分成两个阶段了,那反馈周期不是加长了 吗?”Bob 反驳道。

Joe 点点头,说道:“你说的没有错。但是,根据我们现有的软硬件资源条件,我们目前还无法通过增加资源的方式来缩短所有测试运行的时间。所以我们必须在质量与速度之前做出平衡。这也是我为什么要把那些不易出错的自动化测试集合放在第二阶段构建的原因,这样可以降低但不能完全解除第二阶段构建失败的风险。所以, 这也要求我们大家当第二阶段构建失败时,也要找人尽快把它解决,并且把相关的测试再次放回提交测试阶段中运行,或者在提交测试阶段加入新的测试来补充。” ?

Alice 此时插话,问道:“既然第二阶段构建不常失败,为什么我们不定时运行它,比如每天晚上运行一次呢?这样不是更节省资源吗?另外,如果第二阶段构建运行得慢,那它不是一直都落后吗?”

“因为每次提交阶段构建成功以后就触发第二阶段构建,这样无论如何都比每天晚上运行一次的更多的反馈。因为每天晚上运行一次的话,如果出了问题,我们只能在第二天早上才能发现。对于你的第二个问题,我画一张图来解释。”Joe 找了一张大白纸,在上面开始画了起来。

一会儿功夫,几个示意图就画好了。看到这几个示意图以后,大家恍然大悟。如图 5 所示。从图中我们可以看到:

  1. 当版本 123 的第二阶段构建被触发并正在运行,Alice 又提交了一次,触发了版本 124 的提交构建;
  2. 当版本 124 的提交构建完成之后,由于版本 123 的第二阶段构建仍在运行,所以不再触发第二阶段构建;
  3. 当版本 125 的提交构建完成时,版本 123 的第二阶段构建仍旧在运行,所以也不触发第二阶段构建;
  4. 当版本 126 提交构建正在运行时,版本 123 的第二阶段构建刚完成,此时由于版本 125 的提交阶段构建是一个最近 成功完成的提交构建,所以持续集成服务器就会启动该版本的第二阶段构建,而忽略版本 124 的提交构建。

“那根据我们持续集成纪律,谁的提交让构建失败,就由谁来修复。如果版本 125 的第二阶段构建失败了,就包括版本 124 和 125 两次提交的变更,由谁来修复呢??”Bob 接着问道。

“这个好办,由这两个提交人一起负责修复。如果想确切找到谁的提交有问题,还可以手动触发版本 124 的第二次构建。假如构建成功,说明版本 125 有问题,假如构建失败,说明问题在版本 124 就引入了。”Alice 抢着说道。

讨论到这里,团队成员都达成了共识,(1) 开始加强单元测试的力度;(2) 在反馈速度和反馈质量之间做出折衷,使用二级构建构建的方式。

整个产品的开发非常顺利,马上就要进行版本发布了。团队还会遇到什么问题呢?他们是如何解决的呢?请听下回分解。?

2011-02-17 02:325114
用户头像

发布了 100 篇内容, 共 20.9 次阅读, 收获喜欢 5 次。

关注

评论

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

程序员应如何打破平庸,杜绝淘汰,避免内卷!【强烈建议收藏!】

程序员 ios开发

分解的三要素,从经典中感悟

顿晓

5月日更 分解

消息队列架构设计文档

方堃

模块1作业

圆心角

【LeetCode】数组异或操作Java题解

Albert

算法 LeetCode 5月日更

直呼内行!靠着这份阿里10w字面试总结,我成功收到了4个大厂offer

Java 程序员 架构 面试

基于 MySQL 的消息队列系统架构设计文档

小遵

iOS 面试策略之语言工具-Swift vs. Objective-C

iOSer

ios objective-c swift 面试 移动开发

大促秒杀场景技术方案

Mars

秒杀

辞旧迎新岁岁新

Thomas

matlab

【得物技术】软件工程与PlantUML实战

得物技术

软件工程 UML PlantUML 实战 得物技术

拜托阿里老表爆肝整理10W字Java高级面试精华!帮我成功入职字节

比伯

Java 编程 架构 互联网 计算机

太好用了!斩获3个大厂Offer后,才发现学霸给的JVM笔记有多强大

飞飞JAva

Java

直呼内行!阿里大佬离职带出内网专属“高并发系统设计”学习笔记

Java 程序员 架构 面试

zookeeper的watch机制

大数据技术指南

zookeeper 5月日更

React Hook | 必 学 的 9 个 钩子

程序员海军

最佳实践 方法论 大前端 React Hooks 引航计划

详解 WebRTC 传输安全机制:一文读懂 DTLS 协议

阿里云视频云

阿里云 WebRTC 通信协议 视频云 流媒体传输

想提升查询性能?openLooKeng新下推框架助您一臂之力

openLooKeng

新一代运营保障体系探索

鲸品堂

运营 解决方案 运营商 通信运营商

大厂常问iOS面试题汇总!

iOS猿_员

ios 面试 ios开发

消息队列详细架构设计

Lane

架构实战营 - 模块三作业

Sun

技术干货 | 轻松两步完成向 mPaaS 小程序传递启动参数

蚂蚁集团移动开发平台 mPaaS

ios android 移动开发 mPaaS

在校生丨五面丨拿到阿里offer,你还在边“摸鱼”边抱怨“行业内卷”吗?

Java架构师迁哥

Linux 的 IO 通信 以及 Reactor 线程模型详解

Linux服务器开发

reactor 后端 多线程 Linux服务器开发 网络io

「技术人生」专题第1篇:什么是技术一号位?

阿里巴巴中间件

技术 程序人生 方法论 思维

撸完腾讯T4大佬整理的ThreadLocal笔记,解决内存泄漏只是小儿科

牛哄哄的java大师

Java ThreadLocal

强推!Java大牛熬夜一周梳理的 Spring IOC笔记,收藏一波

飞飞JAva

Java 容器

企业密码管理为何仍然是一个难题?

龙归科技

密码学 密码 弱密码

网络攻防学习笔记 Day7

穿过生命散发芬芳

5月日更 网络攻防

量化AI智能交易软件,马丁策略交易

持续集成之“测试三角形与分段构建策略原则”_Java_乔梁_InfoQ精选文章