持续交付2.0

谷歌当年的TE 要花多大精力解决功能测试自动化用例不稳定的问题

Image

“ 也许最麻烦的方法,才是最好的方法!”

现在,越来越多的软件系统采用了「微服务架构」。尽管这种架构对于多人参与的大系统,为多个功能特性的并行开发与无停机部署提供了便利,但对整个系统的测试与运维提出了新的挑战。

尤其是如何解决后台的功能自动化测试用例不好写,不稳定,不容易维护的问题?

这个棘手问题,谷歌早已遇到,并且花了点儿力气,解决了。

下面是谷歌测试工程师在 2016年 对三种解决方案的摸索过程。

hohoho~~~

谷歌也有复杂的遗留系统,臃肿且不稳定的自动化测试,以及超长的执行时间呀。

hahaha~~~

1

对遗留系统进行翻新,需要新的工具

几年前,我加入了一个工程团队,致力于用新的实现替换遗留系统。因为构建替换系统需要几年时间,所以我们必须保持遗留系统的正常运行,甚至添加功能,同时构建替换系统,这样才不会对外部用户造成影响。

遗留的系统非常复杂和脆弱,以至于工程师们花了大部分时间对 bug 和不可靠的测试用例进行分类和修复,几乎没有时间实现新功能。重写的目标是从遗留系统中学习,并构建更易于维护和扩展的东西。作为团队的测试工程师,我的工作是研究:什么导致了高昂的维护成本,以及如何改进。

我发现了两个主要原因:

  • 紧耦合和抽象不充分使得单元测试非常困难,所以,用了很多端到端的测试用例充当对这些代码的功能测试。

  • 非常大且脆弱不稳定的大型测试。用于端到端测试的基础设施无法为这些被测服务创建和注入 fake 或 mock。因此,测试用例执行前必须找大量资源把这些外部依赖服务都运行起来。这使得我们写的这些测试都成了大型测试。我们目前(2016年)的测试执行平台无法可靠地执行这些测试用例。

2

探索解决方案的过程

第一种(一下能想到的便捷方案)

我试着将大型测试分成多个较小的测试,让这些小的测试用例只测试某个特定的小的功能范围,并减少对外部服务的依赖。

事实证明,这是不可能的,因为遗留代码的架构不合理。要让这种方法起作用,需要对整个系统及其依赖项进行重构,而这就不仅仅是我自己所在的团队负责的这部分了,还要兄弟团队的服务。

第二种(看上去容易的方案)

我把重点放在那些大型测试上,并尝试对在测试某个功能时,不需要的那些服务进行 mock 。这也被证明是非常困难的,因为依赖关系经常变化,而且在一个包含 200 多个服务的图中很难跟踪单个依赖关系。

这种方法只是将所需的工作从维护测试代码转移到维护测试依赖项和 mock 。

第三种(想想都觉得挺麻烦的方案)

在我们面对的典型端到端测试用例中,客户端对几个服务进行了RPC调用,而这些服务又对其他服务进行了 RPC 调用。客户端和所有后端服务上的可传递闭包一起形成了一个超大的拓扑图依赖(根本不是树型!),而且,所有这些服务都必须启动并运行了,才能执行这种端到端测试。

如下图所示,将一个测试用例分成前后两个测试用例。这种方案让测试更小,且更加强大。

新的模式改变了我们测试客户端和服务集成的方式。

  • 第一个测试是为被测试的客户端代码编写单元测试,对 RPC 的stub 进行方法调用。而 stub 本身可以使用Java语言中的 Mockito 这种通用模拟框架模拟。

  • 第二个测试将验证用于驱动模拟的数据对实际服务是否“有意义”。这也可以通过单元测试来完成。在这个单元测试中,使用RPC mock , 对第一个测试得到的客户端调用产生数据进行重放,来调用后续服务的 RPC 处理程序,对其进行验证。

Image

这种集成测试模式适用于任何RPC调用,因此可以像测试前端客户端调用一样,测试后端服务器对下一个后端服务进行的 RPC 调用。当我们始终如一地应用此方法时,我们的收益在于:仍旧测试正确的集成行为,但测试变小了并确保我们正在测试的行为是“真实的”。

为了得到这个解决方案,我不得不构建、评估和丢弃几个原型。虽然为这种方法进行概念验证只花了一天的时间,但我和另一位工程师花了一年的时间才实现了开发人员可以使用的完整工具。

3

推广

当工程师们看到新框架从他们的测试中删除了大量样板代码,他们很快就接受了新的解决方案。为了进一步推广,我和工程团队组织了为期数天的活动,我们的重点是迁移测试用例。

花了几个月的时间将所有现有的单元测试迁移到新框架,弥补覆盖范围的差距,并创建验证 mock 的新测试。

4

效果非常好

当我们转换了大约80%的测试以后,我们就开始比较新测试和现有端到端测试的效果。对比结果如下:

  • 新的测试用例在发现缺陷方面与端到端测试一样有效。

  • 新端到端测试时间约为 3 分钟,而不是 30 分钟。

  • client 测试没有不稳定的。验证测试通常比端到端测试更可靠。

  • 新写的测试都是单元测试,因此可以在 IDE 中运行它们,并逐步调试它们。这样,我们可以很少运行端到端测试,只在检测交互服务的配置时使用,而不再把它们作为功能测试使用。

构建和改进测试基础设施,从而帮助工程师提高工作效率是测试工程师在谷歌做的众多事情之一。

做这个项目,从需求收集一直到成品,让我有机会设计和实现几个原型,推动一个解决方案的全面实现,带领工程团队采用新的框架,并将来自工程师的反馈和实际测量集成到工具的持续改进中。

本文来自于谷歌的测试博客

原文作者:Jochen Wuttke

原文地址:What Test Engineers do at Google: Building Test Infrastructure

原文发表时间:Nov 18, 2016

Image

乔梁老师开课啦~视频课程《持续部署训练营(Python版)》, 限时特价!

你的软件开发效率够高吗?质量够好吗?你的团队多长时间才能向用户实时推送一个生产变更?你的软件在发布时,你是否因担心软件交付质量而感到压力倍增?你是否遇到过部署失败,甚至导致停机的情况?持续部署可以帮助你消除软件交付的痛苦,让你能专注于为客户高价值的需求,而不会因为这些交付执行类问题而花太多精力。本课程通过学练结合,理论结合实战,让你体验如何使用构建-测试-部署管道,进行持续部署。并练习如何在有效监控部署的同时,逐步发布功能特性,并作数据库结构变化。

Image

(扫码订阅)

Image