本文要点
一个成功的微服务测试策略必须有效地管理涉及到的相互依赖的组件。这可能包括隔离、模拟(mock)、虚拟化或其他技术
组织特征影响着对测试技术的选择,例如团队的成熟度和所需的变更速度,例如待重新开发的领域与全新的领域
我们认为,从业务的角度来看,测试方法有三个主要的结果:投入市场的时间、成本和风险。
每种测试技术都有其优缺点。应用程序应该使用哪种方法取决于你的上下文。
本系列的第 1 部分“微服务测试的 12 项实用技术(第一部分)”探讨了在测试微服务时管理依赖于微服务的组件的技术。本文将根据团队的成熟度、变更的速度、投入市场的时间、成本和风险来比较这些技术。
这个比较是基于我们超过 14 个项目的经验,但是我们可能漏掉了一些东西,或者我们的经验不能反映你的经验。所以,请帮助我们完善这个总结,这样我们可以帮助更多的人一起作为一个社区。请在文章下面评论,在 LinkedIn 上或者在 Tweet 上加上 #TestingMicroservices 标签发表。
下表从经理的角度比较了测试微服务的技术。加号(+)表示优势,减号(-)表示负面影响,波浪号(~)表示影响不大或中性。
除了上表中的权衡之外,你的组织特征也会影响测试方法的选择。团队与任务相关的成熟度也将影响你的选择。微服务或其依赖项的项目需求的变化速度也会影响你的选择。例如,竞争市场中的全新项目与处于维护模式的项目将有着不同的价值权衡。
使用给定的测试方法会影响你投入市场的时间、成本、风险和其他一些方面。
下面是这 12 种技术的高层次概述。
1. 使用另一个微服务的测试实例来测试您的微服务。
团队成熟度的影响很小,因为团队不需要了解测试替身的类型以及如何使用它们。如果你是软件开发和测试的新手,那么用这种方式进行测试比较容易。
这种技术适合任何变更速度。如果速度很快,团队就会得到关于 API 之间兼容性问题的快速反馈。当节奏变慢时,也没什么关系。
随着复杂性的增加,大多数项目投入市场的时间会变慢。这是软件团队的典型陷阱,也是许多大型企业的技术债务来源。这项技术很容易就能开始用起来,因为它几乎不需要额外的基础设施或测试替身的知识。
许多公司在最初的测试之后仍然使用这种方法,这导致了技术债务的快速积累,最终会减慢开发团队的速度,因为被测试系统的复杂性会随着其组件的数量呈指数级增长。
大多数项目需要结合包括测试替身在内的测试技术,以达到足够的测试覆盖率和稳定的测试套件——你可以阅读关于这个称为测试金字塔的更多信息。适当地使用测试替身,你可以更快地投入市场,因为你测试得比其他情况下要少。
成本会随着复杂度的增加而增加。因为你不需要太多额外的基础设施或测试替身的知识,所以这项技术的初始成本并不高。但是,成本可能会增加——例如,你需要更多的测试基础设施来承载必须一起测试的相关微服务组。
测试依赖项的测试实例可以减少在测试替身中引入问题的机会。遵循测试金字塔制定一个合理的开发和测试策略,否则你可能会得到巨大的 E2E 测试套件,这些套件维护成本高,运行速度慢。
只有在仔细考虑过测试金字塔之后,才能谨慎地使用这种技术,不要落入倒置测试金字塔的陷阱。
2. 使用另一个微服务的生产实例来测试您的微服务。
在使用产品实例进行测试时,团队需要格外小心,相比于使用测试替身的团队,必须要更加信任这个团队。
投入市场的成本和时间与第一种技术没有区别。你的团队与产品发布周期维系在一起,这可能会延迟他们的测试。
团队需要格外小心,因为这种技术的风险比测试替身要高得多。连接到生产系统的测试可以更改生产系统的状态。仅针对无状态 API 或团队精心选择的在生产中可以使用的测试数据使用此方法。
使用生产实例进行测试通常意味着很难模拟假设的失败场景和错误响应。在设计开发和测试策略时,请记住这一点。
对依赖的生产实例进行性能测试可能会给生产系统带来不必要的压力。
这种技术通常适用于简单、稳定、非关键的 API,这是一种罕见的用例。除非你有明确的理由,否则不要这样做。
3.使用第三方依赖项测试微服务。
团队需要知道如何在第三方依赖项中设置测试数据,但其他方面不需要特别的经验。
你的团队受到第三方发布周期的约束,这可能会减慢他们的速度。
组织可能必须付费使用第三方 API 进行测试,因为第三方通常对每个事务收费。这在测试性能时尤其重要。
4. 使用遗留的非微服务内部依赖项来测试微服务。
这种技术就微服务的新领域和旧遗留系统之间的契约问题提供快速反馈周期,从而降低风险。
除了技术 1 的所有缺点之外,你还需要记住,遗留系统常常存在测试环境可用性和测试数据设置方面的问题。
5. 使用非软件(硬件)依赖项测试微服务。
团队需要知道如何在硬件依赖项中设置测试数据。
一般来说,硬件的变化速度比较慢,但是价格可能会比较贵。即使仅要得到一个用于测试目的的硬件实例,成本也会很高。当你需要更多的硬件来由不同的团队或构建\流水线并行运行测试时,成本可能会显著增加。
与前一项技术类似,微服务和硬件之间有一个快速的反馈周期,这可以降低风险——但是硬件可能存在测试环境可用性和测试数据设置方面的问题。
6. 模拟(进程内或通过网络/远程)。
团队必须知道如何使用进程内的模拟。
模拟有助于降低测试用例的复杂性,减少调查和重现问题的时间,但是会带来 API 之间存在差异的高风险。它们通过对其他系统的行为进行假设来降低复杂性,但是可能会对 API 的工作方式做出不正确或过时的假设。项目需求的变更速度越快,保持模型最新就越重要。请参阅契约测试以了解减少这种风险的策略。
需要一定的时间以开始使用模拟和定义缓解策略(如消费者驱动的契约、集成的测试或集成测试)来确保模拟是最新的。模拟可能会过时,而成功地运行一个过时的测试套件将使你对质量抱有错误的信心。
你的技术栈中可能没有免费的模拟解决方案,因此你可能必须自己开发一个或者购买一款商业产品。
模拟允许你设置低粒度的故障和假设的场景,从而提升测试覆盖率。
在大多数用例中,使用模拟是一个好主意,它可以是最健康的测试金字塔或测试蜂巢的一部分。模拟通常是测试复杂系统的基本技术。
7. 桩(进程内或通过网络/远程)。
模拟使用特定于测试的对象替代微服务依赖的对象,该对象验证微服务是否正确地使用了它,而桩使用特定于测试的对象替代它,该对象为微服务提供测试数据。两者的取舍很是相似。
内部开发复杂依赖项的桩可能非常耗时和昂贵。建议选择现成的模拟、模拟器(simulators)或服务虚拟化工具,而不是桩。
8. 模拟器(进程内或通过网络/远程)。
团队必须知道如何使用你选择的模拟器。模拟器通常为开发人员或测试人员提供个别的方式与它们进行交互。
组织通常为广泛使用的或稳定的 API 创建模拟器,你可以快速开始使用这些现成的模拟器。快速、早期的测试缩短了你投入市场的时间,并且使用现成的、稳定的模拟器可以节省成本。它们可以提供大量预定义的错误响应和假设场景,以提升测试覆盖率。
为复杂的依赖关系开发自己的内部模拟器可能非常耗时和昂贵。开发你自己的模拟器可能会引入模拟器与实际依赖之间的差异,并在测试套件中创建错误的信心。
然而,很容易用复杂的模拟器替换复杂的依赖项,并且忘记必须随着依赖项的演变使其保持最新。应考虑持续维护的成本。
该技术使你可以模拟网络问题,这对于测试依赖于网络的微服务架构非常重要。
尽可能选择现成的模拟器。只有当你的团队对真正的依赖项和模拟有大量经验时,才能够构建内部模拟器。
9. 服务虚拟化(通过网络/远程),也称为 API 模拟。
你的团队必须知道如何进行服务虚拟化,并且必须选择附带教程和其他材料的工具。
服务虚拟化工具有助于保持虚拟服务的最新状态。项目需求的变化速度越快,就越需要防止虚拟服务过时。服务虚拟化工具提供了一些技术和组件,其中之一是“记录和回放”,这是一种使你可以快速为经常变化的 API 重新创建虚拟服务的技术。请参阅“契约测试”以了解其他降低这种风险的策略。
如果采用其内置的经过充分测试的模式,那么使用现成的服务虚拟化产品可以帮助你更快地进入市场。熟悉现成工具的顾问可以与开发人员和测试人员密切合作,基于许多项目的经验帮助你选择一个微服务的测试方法。
当团队刚开始接触微服务时,使用现成的工具可以节省成本,因为那些供应商可以帮助你避免常见的错误。然而,随着时间的推移,你对商业产品的使用可能会变得昂贵。建议根据 ROI 预测选择供应商。
使用没有支持合同的开源工具可能会导致你的开发人员和测试人员花费时间来修复 bug 并维护文档和培训材料。
服务虚拟化有助于降低被测系统的复杂性。这些工具可以帮助你管理你的假设。大多数服务虚拟化工具已经在市场上存在很多年了,它们的设计都考虑到了大型和独体集成系统。选择最适合你的微服务架构的开源或商业工具——但是任何虚拟服务都可能过时,因此请参考你的供应商对于缓解策略的建议。
10. 内存数据库。
团队必须了解切换为使用内存数据库进行测试的技术风险。
因为这种技术使用一个内存数据库,所以在此变更的速度影响很小。当为了开发或测试的目的做新数据库的供应存在问题时,它可以显著减少项目投入市场的时间。
许多内存数据库都是开源和免费的,这显然有助于降低许可成本。但是内存数据库在极端情况下的表现可能与实际数据库不同。应将对实际数据库执行测试作为测试策略的一部分,以便观察实际数据库和内存数据库之间的差异。
11. 测试容器。
你的团队必须知道如何运行测试容器。
由于测试是在实际依赖上(在一个容器中)进行的,所以变更的速度对这个解决方案影响很小。
运行第三方服务或服务虚拟化测试容器可以减少团队之间的依赖,并允许每个团队以自己的速度移动。这些容器还可以显著降低测试基础设施的成本。
运行一个测试容器,而不是依赖共享实例,可以减少环境问题影响测试结果的可能性。
将商业数据库的开发版作为开发和测试的测试容器来运行,可以降低你的许可成本。将生产型商业数据库作为容器来运行是非常昂贵的。
测试容器可以配置得与真正的依赖项不同,从而导致对测试套件的错误信任。应确保将容器数据库配置为与生产数据库相同(例如,使用相同级别的事务隔离)。
12. 装入箱中的遗留系统。
当遗留系统可以轻松地移植到容器中时,你的团队的成熟度只有中等程度的影响,但是如果你的团队需要重构旧遗留系统中的部分配置和代码以使其在容器中工作,则会产生更多的影响。工作量取决于项目,所以首先要研究和评估工作的规模。
遗留基础设施需要时间来准备。在容器中就遗留系统方面的设置进行了最初、潜在的大量投资之后,启动和运行新环境(容器)所花费的时间和金钱要比典型的硬件设置少几个数量级。
这种技术减少了引入测试替身和实际系统之间的差异的可能。应确保将容器遗留系统配置为与生产系统相同,以便生产环境和测试环境之间不存在显著差异。
总结
我们从一名管理者的视角探讨了在测试微服务时管理微服务依赖关系的技术,并根据团队成熟度、变化速度、投入市场的时间、成本和风险对它们进行了比较。
这些信息应该填补一些空白,并帮助你定义开发和测试策略(包括测试金字塔),以缩短投入市场的时间,降低成本,并提高组织内的质量。
每种方法都有其优点和缺点,哪种选择对你的应用程序更有价值取决于你的环境。本文的第 3 部分将包括案例研究,重点介绍我们的客户如何应用这些知识来做出决策。
如果您发现本文有任何不清楚的地方,或者您有任何特定于项目的担忧或问题,请通过邮箱联系作者 Wojciech Bulaty (wojtek@trafficparrot.com)和 Liam Williams(Liam Williams at liam@trafficparrot.com )。
作者简介
Wojciech Bulaty 专注于敏捷软件开发和测试架构。他在敏捷、自动化、XP、TDD、BDD、结对编程和整洁编码方面有十多年的实际编程和领导经验。他最新提供的服务是 Traffic Parrot ,通过提供 API mocking 和服务虚拟化工具帮助使用微服务的团队加速交付、提高质量和缩短投入市场的时间。
Liam Williams 是一位自动化专家,专注于使用高质量的软件解决方案改善容易出错的手工流程。他是一个开源贡献者和一些小型库的作者。最近,他加入了 Traffic Parrot 的团队,将注意力转向了迁移到现代微服务架构时测试体验的改善问题上。
原文链接:
Testing Microservice: Examining the Tradeoffs of Twelve Techniques - Part 2
评论