测试管理 Just Say No to More End-to-End Tests (译文)

陈恒捷 · 2015年04月28日 · 最后由 夏日鸣虫 回复于 2016年12月21日 · 1888 次阅读
本帖已被设为精华帖!

原文作者:Mike Wacker
原文地址:http://googletesting.blogspot.com/2015/04/just-say-no-to-more-end-to-end-tests.html
译者:chenhengjie123

在你生命中的某些时刻,你想起一部电影,你和你朋友都想看,但你和你的朋友都后悔看了这部电影。或者你还记得当你的团队以为他们发现了他们产品的下一个 “杀手级功能”,但上线后却是功能炸弹。

好的想法通常会在实践中失败,而在测试领域,一个听起来相当不错但实践中经常失败的概念是建立围绕端到端测试的测试策略。

测试人员可以投入他们的时间来编写任何类型的自动化测试,包括单元测试、集成测试以及端到端测试。但这个策略把大部分时间投入到端到端测试中以整体验证产品或服务。通常情况下,这些测试会模拟真实用户使用场景。

端到端测试理论

当你觉得依赖端到端测试是一个坏主意时,肯定会有人通过这个主意在理论上的合理性和存在意义来说服你。(译者注:原文是 While relying primarily on end-to-end tests is a bad idea, one could certainly convince a reasonable person that the idea makes sense in theory. 实在不知道怎么翻比较合适,麻烦大伙给下意见,我后面更正)

在开始之前,我们先来看一下 Google 的 ten things we know to be true(十件我们知道正确的事)中的第一条:“关注用户,剩下的一切都随之而来(Focus on the user and all else will follow)”。根据这条准则,关注真实用户场景的端到端测试听起来是一个很好的主意。另外,这种策略在许多地方都呈现出:

  • 开发者喜欢它,因为它能转让大部分(如果不是全部)测试工作给别人。

  • 管理者和决策者喜欢它,因为模拟真实用户场景的测试可以帮助他们确定一个失败用例对用户的影响有多大。

  • 测试人员喜欢它,因为他们经常担心漏报了一个会被用户找到的 bug 或者写出一个不能验证真实场景的用例。从用户角度编写用例能避免上面两个问题同时给予测试人员更好的 “我完成测试了” 的感觉。

实践中的端到端测试

既然这个测试策略在理论上听起来这么赞,那么它在实践中哪里出问题了?作为示范,我基于自己收集到的我和其他测试人员的共同经历来讲述下面这个故事。在故事中,一个团队正在建立一个在线文档编辑服务(比如: Google Docs)

我们假设这个团队已经有比较不错的测试基础设施。在每个晚上:

  1. 最新版本的服务会被构建

  2. 这个版本会被部署在团队的测试环境

  3. 所有端到端测试都会在这个测试环境中进行

  4. 一个包含了测试结果的测试报告会通过电子邮件形式发给整个团队

最后期限在我们团队不断为下一个版本编写新功能的过程中很快来到。为了保证产品处于高质量水准,他们要求在功能被认定为完成前,端到端测试用例通过率至少达到 90% 。现在,离最后期限只有一天了:

剩下的天数 通过率 备注
1 5% 所有东西都有问题!登录到服务的功能有问题。几乎所有测试都需要用户登录,所以几乎所有用例都失败了
0 4% 一个和我们服务有依赖关系的搭档团队昨天在它们的测试环境上部署了一个无法运行的版本
-1 54% 一个开发在昨天(也许是再前一天)搞坏了保存功能。几乎一半的用例在需要保存文档。开发花了差不多一天的时间来确定这到底是一个前端的 bug 还是后端的 bug 。
-2 54% 确定了昨天那个保存问题是前端的 bug ,开发花了半天时间来查找具体哪里出问题。
-3 54% 一个很烂的 fix 在昨天被提交了。这个错误仍然被触发到,然后一个正确的 fix 终于在今天提交了。
-4 1% 我们测试环境使用的实验室出现了硬件故障
-5 84% 很多大 bug(如无法登录,无法保存)背后的小 bug 被发现了。团队还在修复小 bug 中。
-6 87% 我们应该能达到 90% 以上,但由于某些原因,还没达到
-7 89.54% (达到 90% 左右了,已经可以接受了)昨天没有任何 fix 被提交,所以昨天的测试达不到 90% 肯定是由于碎片造成的。

分析

抛开各种问题,这个测试最终还是找到了真正的 bug 。

好的地方

  • 会直接影响到用户的 bug 都在到达用户之前被验证和修复了。

不好的地方

  • 团队延迟了一周才达到他们的里程碑(并且加了不少班)。
  • 寻找导致端到端测试失败的问题根源非常痛苦且花时间。
  • 搭档团队环境的问题和实验室问题导致的失败出现了好几天。
  • 在大的 bug 后面还隐藏着很多小的 bug 。
  • 端到端测试中有几次由于碎片导致结果不稳定。
  • 开发需要等到第二天才能知道自己的 fix 是否正确。

那么我们现在知道了端到端测试策略在实践中做得不好的地方了,我们需要改变我们的测试来避免这些问题。那么应该怎么做?

测试真正的价值

通常情况下,一个测试人员在找到一个失败的用例时,他的工作已经完成了。登记完 bug 后,接下来的修复工作就交给开发了。然而,为了确定端到端测试策略行不通的原因,我们需要跳出这个场景,并结合前面提到的第一条准则来思考。如果我们 “关注用户(剩下的一切都随之而来)”,我们必须自问一下:一个测试用例的失败到底能为用户带来多大的利益。下面是答案:

一个失败的用例并不能直接给用户带来利益

虽然这个结论看起来会让人很惊讶,但这是事实。如果一个产品能用,那么无论测试结果说明说它能否能用,它都是能用的。如果一个产品用不了,那么无论测试结果说明说它用不用得了,它都用不了。所以,一个失败的测试用例并不能直接给用户带来利益。那么什么能给用户带来利益呢?

一个 bug fix 直接给用户带来利益

用户只会对不正确的行为 —— bug —— 消失时感到高兴。显然,为了修复一个 bug ,你必须知道它的存在。为了知道 bug 的存在,理想地你会有执行内部测试来发现 bug(因为如果测试没找到 bug ,那么用户就会找到)。但在整个过程中,从一个失败的测试里面找 bug 来修复,它的价值只会在最后一步体现出来。

阶段 测试用例失败 开 bug 修复 bug
是否产生价值 No No Yes

因此,在评估一个测试策略的价值时,你不能只看它如何找到 bug ,你还需要评估它怎么让开发去 fix(甚至避免产生)这些 bug 。

建立良好的反馈闭环

测试需要建立起一个反馈闭环,通知开发人员这个产品是否能用。理想的反馈闭环有下面这些特征:

  • 它很快。没有开发者希望等待几个小时甚至几天才能知道自己的变更是否正常工作。有时候这个变更并不起做作用 —— 毕竟没有人是完美的 —— 而反馈闭环需要进行数次才能完成。一个快速一点的反馈闭环会引导向更快速的修复。如果这个闭环足够快,开发甚至可以在提交变更前执行测试。

  • 它是可靠的。没有开发人员想花费数个小时来调试一个不稳定的测试( 译者注:flaky test,这个找不到合适的词来翻译,就理解为不稳定的测试好了 )。不稳定的测试让开发人员不再信任测试结果,所以最终即使它真的找到产品问题,它的测试结果也很有可能会被忽略。

  • 它能隔离故障。为了修复一个 bug ,开发人员需要找到导致这个 bug 产生的那数行代码。当一个产品含有上百万行代码时,任何地方都有可能存在 bug ,找这些导致某个特定 bug 的代码无异于大海捞针。

从小处着手

那么我们可以造出这个理想的反馈闭环吗?可以的,但要从小处着手。

单元测试

单元测试只取产品中的一小部分并在隔离环境下对它进行测试。它们更合适用于建立这个理想的反馈闭环:

  • 单元测试都很快。我们只需要构建一个小的单元来执行测试,同时这个测试也趋向于小型化。实际上,十分之一秒的执行时间对于单元测试来说都是很慢的了。

  • 单元测试都是可靠的。 简单的系统和小的单元遭受到碎片的影响要少得多。此外,单元测试的最佳实践 —— 完全隔离的测试 —— 会完全移除掉碎片的影响。

  • 单元测试能隔离故障。即使产品有上百万行代码,如果一个单元测试失败了,你只需要查找单元测试的被测单元就能找到 bug 了。

编写有效的单元测试需要依赖管理、moking、以及隔离测试领域的技术。我不会在这里详细讲述这些技术,但作为一个引子,一个通用的适用于新的 Google 员工(或者非 Google 员工)的例子是 Google 如何构建测试一个秒表程序。

单元测试 vs. 端到端测试

使用端到端测试,你需要等待:首先构建整个产品,然后把它部署到环境中,最后才是执行测试。当测试执行时,不稳定的测试将由于碎片存在而一直存在。而且即使这次测试找到了一个 bug ,这个产生 bug 的代码也有可能存在于产品的任何一个地方。

虽然端到端在模拟真实用户场景这方面做得更好,这个优势很快就会被端到端反馈闭环的劣势盖掉:

单元测试 端到端测试
高速度
高可靠性
故障隔离
模拟真实用户场景

集成测试

单元测试有一个主要劣势:即使这些单元在隔离状态下运行的很好,你不知道他们集合到一起后是否也能运行地很好。但即使这样,你也不需要端到端测试。为了确认他们集合后的运行情况,你可以使用集成测试。一个集成测试需要数个的单元 —— 大部分情况下是 2 个 —— 然后在整体上测试他们的行为,验证他们是否能连贯地工作。

如果两个单元没有被正确地集成起来,为啥你要在抛弃够编写更小、更专注的集成测试而去编写端到端测试来查找 bug ?当你需要从更大范围进行测试时,你只需要把范围扩大一点点来验证各个单元集成后能正常工作。

测试金字塔

即使有了单元测试和集成测试,你还需要有少量的端到端测试来整体验证这个系统。为了找到这三种测试类型的平衡,最直观的方式就是测试金字塔。这里是一个精简的、来自 2014 Google Test Automation Conference测试金字塔

大量的测试都是在金字塔底部的单元测试。越往上看,你的测试范围将越来越大,但同时测试的数量(金字塔的宽度)越来越少。

作为一个开拓者(译者注:原文是 good first guess ,没找到很好的翻译,就用开拓者来代替吧), Google 建议采用 70/20/10 的划分方式:70% 单元测试,20% 集成测试,10% 端到端测试。实际比例会根据各个团队的情况有所不同,但总体上,它应该保持这个金字塔的形状。尝试避免以下的反模式:

  • 把金字塔倒过来变成雪糕形状。团队主要依赖端到端测试,执行少量集成测试和更少的单元测试。

  • 沙漏型。团队一开始有很多单元测试,然后在该需要使用集成测试的地方使用端到端测试。沙漏型在底部有大量单元测试,在顶部有大量端到端测试,但中间只有少量的集成测试。

就像真实世界中金字塔是最为稳定的结构,测试金字塔也应该是最稳定的测试策略。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 12 条回复 时间 点赞

文中提到的端到端测试的缺点

团队延迟了一周才达到他们的里程碑(并且加了不少班)。

原因没说, 估计就是下面的这些原因。

寻找导致端到端测试失败的问题根源非常痛苦且花时间。

如果测试部门也能用上淘宝鹰眼或者 twtter 的 zipkin, 我觉得排查问题会少很多时间。
商业产品也有了, 比如 newrelic, oneapm 等。这些产品都是来自于 google 的论文和内部产品。
为什么 google 测试部门没有用起来, 表示疑惑。

搭档团队环境的问题和实验室问题导致的失败出现了好几天。

搭档团队环境出了问题, 这个有几种解法。
通过接口测试, stub 来替换有问题的模块
使用可用的老版本替换
分层测试

在大的 bug 后面还隐藏着很多小的 bug

这个端到端测试的确是搞不定的。 需要做好针对模块的特定测试。端到端的测试不能测试完全。
需要结合测试建模,或者一定的白盒和黑盒的探索测试。

端到端测试中有几次由于碎片导致结果不稳定。

这类问题是无解的。需要分层测试。后端总有一些超时或者网络拥塞,或者磁盘满。
我的建议是这些不稳定的 case 同样也是非常重要的测试场景数据。不稳定也具备参考价值。让你了解真实的系统表现。

开发需要等到第二天才能知道自己的 fix 是否正确。

整体的测试的确会很慢, 需要分层测试来解决。搭建环境也很费劲。 我推荐用 docker vagrant 这类工具来解决环境问题。
如果是持续交付或者持续集成的环境。 速度应该很快。

我的看法

  1. 端到端测试可以发现很多问题。他能模拟比较真实的环境。可以建立一些业务模型。让所有人熟悉业务流。
  2. 端到端测试可以用来反推各个模块的测试。 比如录制各个模块之间的交互。 自动生成对应的接口测试。 单元测试理论也可以自动生成, 不过这种后补的单测没有太大意义,不符合单测的定位。
  3. 比如有一些非常零散的多模块通过端到端测试可以较为理想的覆盖他们。而不用去考虑各种复杂的接口拆解。可以省一些时间。 所以我总体上赞同 google 的观点。 但是我喜欢端到端测试。觉得他的比重应该高一些。70% 的单测我相信中国 99% 的团队都达不到。在研发人员质量参差不齐的情况下。 他们的单测根本靠不住。 所以集成测试和端到端测试应该成为国内测试人员重点关注的领域。除此之外一些专项测试也是非常有必要的。

端到端测试工具的支持

  1. 环境管理工具。 vagrant docker
  2. Trace 技术。比如覆盖率工具, Trace 和 Debug 工具。 我赞同 Trace,不太喜欢 debug
  3. 监控平台。Twitter 的 zipkin,淘宝鹰眼,京东和去哪儿也有类似的各种系统。 推荐看看 ZipKin。 商业工具主要是 newrelic,oneapm。开源的 ELK 组合技术栈 Logstash+ElasticSearch+Kibana
  4. 持续集成和持续交付
  5. 接口测试。利用端到端测试的场景。慢慢积累起来业务模型和接口测试体系

没有良好的工具支撑,端到端测试这种复杂测试场景是没法管理好的。

#1 楼 @lihuazhang 嗯,我把原文补上了。这句大意就是端到端测试在理论上有合理性和存在意义吧。

老实说,对于复杂业务的系统,即使有丰富的单元、集成和端到端测试,还是脱离不了大量的手工测试,所以关键流程上我还是希望有端到端的测试用例

#4 楼 @seveniruby 工作经验多了解层面高很多啊!赞!
确实现状是单测在国内的比例不高,大部分做自动化的都是端到端,Google 的以单测为基础的测试体系在国内很难推动(开发会说影响进度,不干)。
我个人比较赞同文中关于只有 bug fix 才能创造价值的观点。同时我觉得端到端通过监控/完整的日志可以尽可能让开发容易定位问题所在(前提是程序有良好的日志/提供监控的接口)。

好几年前做对日外包的时候,测试就是这样 3 层的,基本上是各层的负责人负责设计测试,执行由出体力的人们做
不过前提是有很详细的设计,每层的人,都理解自己做的东西
有时候我们测试不好,原因之一就是不清楚要测试什么

这里的端到端是否是指包含用例管理,测试任务管理,测试任务触发,测试执行,测试结果收集以及邮件发送全部集成在一套环境中,测试用例覆盖各种用户使用的业务场景的集成测试环境啊?这个貌似在小公司挺难的吧。
移动应用的实际用户业务场景测试应该在手动测试中都要覆盖的吧,端到端的测试中提到的场景覆盖是指覆盖这些内容吗?如果不考虑 UI 自动化的结果比对准确性等问题,是不是基于业务流程的 UI 自动化就可以实现这个端到端测试的期望了?

当你觉得依赖端到端测试是一个坏主意时,肯定会有人通过这个主意在理论上的合理性和存在意义来说服你。

这句话翻译的不好,但是我也帮不了你。。

#8 楼 @chenhengjie123 个人觉得他强调单元测试的重要性其实可以理解为测试前移的概念,越早发现问题修复的成本就越低,不管是时间成本还是人力成本或其他。到了进行端到端测试的阶段,产品已经成型。我们以前做测试还做代码走读等,目的就是要尽早发现问题,当然移动应用的开发周期太短,实在不好对比操作
@seveniruby 有没有接口测试和分层测试相关的比较系统点的资料,层层深入的那种,在网上找了点,感觉大部分都在说概念,不好意思又做伸手党了

#9 楼 @cissysnail 接口测试和分层测试 这个和业务有很大的关系。

#10 楼 @lihuazhang 额 那我入职之后再好好学习吧

#4 楼 @seveniruby 还有灰度发布,不然直接把用户当小白鼠了;端到端测试虽然土,但是很直接的验证方式

#7 楼 @cissysnail 额,你前面提到的测试任务触发,测试执行,测试结果收集以及邮件发送用 Jenkins 跑你的测试就能做到了。小公司确实挺难,因为配环境比较麻烦,而且迭代速度快的话自动化测试(按照你的描述应该是用自动化的端到端测试)测试用例维护成本高。

手动测试大部分情况下是端到端测试(测试中包含系统的两端,如服务端和客户端)。基于业务流程的 UI 自动化是可以实现端到端测试。

这个文章的主旨是仅靠端到端测试创造的价值不够高(开发修 bug 时间慢),而且原文是 Google Test Blog 的,所以应该没考虑小公司。不过他的一些思想(指定测试策略时不仅要考虑能否覆盖所有功能,还要考虑修复 bug 的时间成本)小公司其实可以借鉴。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册