导读:自动化测试是实现软件持续交付的重要一环,当团队日积月累要维护大量旧系统时候或者要升级一个旧系统时候,测试工作如何进行更加需要方法,本文介绍 Google 测试工程师如何处理上述问题,由高可用架构志愿者翻译整理如下。
在最近的一篇文章中,我们广泛讨论了测试工程师在 Google 做什么 [1]。 其中可能的工作罗列如下:
-
自动化产品发布版本的手动验证过程,以便开发人员有更多时间来响应潜在的真正影响发布的问题。
-
设计和实施一种自动化方式,来跟踪并向开发人员展示 Android 电池使用情况,以便他们立即知道新功能将导致用户耗尽电池。
-
量化包含十亿级别数据的产品,比较新版本重新生成的数据集的质量是否优于当前在生产环境中的数据集。
-
编写一个自动测试套件,验证呈现给用户的内容,根据用户的兴趣,是否达到一个可接受的质量标准。
-
阅读有关新功能的工程设计方案,并提供有关如何和在何处构建可测试的建议。
-
调查用户通过我们的反馈跟踪系统提交的相关堆栈跟踪,并搜索代码库以查找正确的所有者进行升级。
-
参与协作,确定生产环境某个故障中断的根本原因,然后精确定位需要添加的测试,以防止未来出现类似的问题或故障。
-
组织一个任务小组,在测试无障碍功能时向整个公司的团队提供有关最佳实践的建议。
在下面,我们将介绍 TE (test engineer,下同)可能做更重要的另外一个方面工作:
建立和改进测试基础设施,使工程师更有效率。
介绍的
第
一个场景就是:
翻新旧系统需要新工具
几年前,我加入了一个工程项目组,主要任务是开发一个新系统替换旧系统。因为构建替换过程需要几年,我们需要保持旧系统正常运行,甚至在旧系统上添加新功能,同时慢慢替换为新系统,这样才不会影响用户使用。
然而旧的系统是如此复杂和脆弱,工程师要花费大部分时间来分类并修复 bug 及进行相关测试,以至于没有时间实现新系统。新系统的目标是实现所有老系统功能的基础上,并使之更容易维护且扩展性更好。作为团队的 TE,我的工作是了解高维护成本的成因及如何改进。
我发现两个主要问题:
解决方案
首先,我尝试将大测试分成更小的测试的可能性,小测试可以聚焦特定几个功能,并减少依赖服务的数量。但是,在结构不良的旧系统代码中,发现这个想法是不可能的,如果要按这种方法工作将需要重构整个系统及其依赖项,这不仅仅是测试团队可以完成的工作。
第二种方法,我尝试进行大的测试,并试图将非测试的功能的调用进行 mock。这最终证明也是非常困难的,因为依赖经常改变,并且单个依赖很难在 200 多个服务中进行追踪。最终,这种方法只是将所需的工作从维护测试代码转移到模拟和维护测试依赖。
我的第三个也是最后一个方法,如下图所示:
使小测试用例更加强大
。在我们面临的典型的端到端测试中,客户端对几个服务进行了 RPC 调用,这些服务又 RPC 调用了其他依赖服务。客户端和所有后端服务的调用闭包一起形成了一个大的依赖图(而不是树!),这一切都必须在端到端测试中运行。
新模型改变了我们如何对客户端和服务端进行测试,仅运行客户端来执行几个 RPC 调用,然后观察相关依赖调用是否正常的做法不太适合,我们对 RPC stub 的代码编写单元测试,
Stub 本身是用一个常见的模拟框架(如 Java 中的 Mockito)来完成的。
对于每个这样的测试,还有其他的测试来证明模拟数据对于实际服务“有意义”,这也通过单元测试来完成,通过重放客户端调用服务器来获得的相同数据。
这种集成测试模式适用于任何 RPC 调用,因此可以测试后端服务器对另一个服务器执行的 RPC 调用或者客户端调用。 当我们都应用这种方法时,我们有了可以保证集成测试正确的小测试用例,并确保我们测试的行为是“真实的”。
为了达成这个方案,我建立、评估以及丢弃好几个原型, 虽然构建原型及验证只花了一天时间,但是我
和另一个工程师
花了一年时间,来将它编程团队成员可以使用的一个工具。
采纳使用
当看到新框架从他们项目中替换了大量测试代码时,工程师非常快地接受了新方案。为了进一步推动其采用新框架,我与工程团队组织了多天活动,用于迁移测试用例。将现有单元测试迁移到新框架,缩小覆盖差距,并创建验证 mock 的新测试,这些需要几个月的时间。一旦我们完成了大约 80% 的测试用例,我们就开始比较新测试框架和现有端到端测试的效果。