用于性能测试的服务存根:简介
随着测试项目的复杂性不断增加,越来越多的被测系统的测试流程受到依赖系统的影响。当我说“依赖系统”时,我指的是:

不受当前开发影响的遗留系统
属于另一个组织的第三方服务
您的组织开发的系统,路线图不明确
依赖系统的存在使每个手动或自动测试项目都处于如下图所示的情况。

测试参与者 - 在图中,我展示了一个测试项目,该项目对被测系统进行压力测试,以手动和自动化的不同方式验证其质量。
被测系统 (SUT) - 由实现业务需求的异构服务和基础设施组成的复杂架构。
附加系统 - 这些服务与最终应用程序协作,但超出了项目管理范围。可能他们的一些要求尚不清楚。这些是依赖关系。
在上图中,关注箭头也很重要。这些箭头描述了系统的边界和用于交换消息/信息的接口:

红色箭头表示在测试工具(本例中为 JMeter)中运行的测试规范。
灰色箭头表示存在测试人员知之甚少的功能关系。如果您太晚才意识到依赖关系破坏了您的测试逻辑,这可能会浪费您的时间。因此,提前计划,找出依赖关系,存根它们,制定计划并继续测试。
依赖系统的存在会在整个测试项目(手动和自动测试)中产生一系列令人不快的影响:

脆弱性 - 随着不受控制的依赖项数量的增加,测试变得更加脆弱,因为当问题在于依赖项而不是 SUT 时,您可能会得到失败的测试,从而导致测试不可靠。
不稳定 - 当 SUT 启动时,依赖性可能会导致系统瘫痪,从而影响与 SUT 没有明确关联的测试结果。
耗时 - 设置测试数据可能需要数天/数周的时间,并且可能容易出错。
不可用性——测试团队可能会花时间等待依赖系统的可用性。
沮丧——事情的人性方面:
测试人员 - 您可能会因为无法有效地完成工作而感到沮丧
经理 - 您可能会感到沮丧,因为您的团队因工作受阻而浪费时间
为了消除或大大减少这些影响,一种解决方案是将 SUT 上执行的测试过程与不受控制的依赖关系解耦。解耦的一种方法是采用存根接口,其目标是复制依赖关系的行为。通过这种方式,测试过程不会像原始依赖系统那样遇到不可预测的行为。因此,测试范围现在将包括存根服务,因为它们是测试过程的一部分。因此,我们将在图表中的测试范围中添加一个新端点。

要在测试计划中创建存根接口,我们需要:

添加一个名为存根服务的新系统,该系统复制要存根的接口
根据计划的测试过程定义必须存根哪些调用
了解存根是测试套件的一部分并且包含在测试范围内
在上图中,我在测试范围中添加了一个新实体(存根服务)。存根服务在查询时的行为类似于原始依赖项,只是它使用与测试范围一致的特定消息进行响应。存根可以重现功能特性以及非功能特性,例如响应时间或慢速连接。

让我们了解消息/信息交换的流程:

红色箭头与上图具有类似的功能,但略有不同:测试团队已经使用存根和 SUT 生成了前提条件
绿色箭头 - 是存根接口,它从真实的依赖系统中再现所有可能的请求/响应的子集。您如何决定应该存根哪些请求/响应?这取决于两个因素:
测试覆盖率 - 测试团队必须确保 SUT 的质量。这个目标是通过测试覆盖率来实现的。更多的测试覆盖率需要更复杂的存根。
存根设置工作 - 测试团队负责设置存根接口并维护它们。因此,必须相应地分配资源。理解这一点很重要,因为某些存根的维护可能很复杂,并且与原始测试计划相比,工作量可能会变得非常出乎意料。
总结本节:存根可能是复杂测试项目成功的关键。

虚拟化作为服务存根的捷径
开发存根服务需要大量的规划和实施工作。有时,项目成员会采用快速而肮脏的解决方案来加速软件生命周期活动。他们假设他们需要短时间的存根使用(例如开发一项功能、测试一项功能)。快速而肮脏的解决方案很有吸引力,但它往往会:

生命周期很短,随着时间的推移无法保证再现性。
仅由一种环境使用,通常是开发它的环境。
简单的存根解决方案基于硬编码和/或参数化数据。还有基于数据模型解决方案的更复杂的存根服务。存根服务的设置变得更加复杂,有时需要适当的培训,但对于具有更广泛目标的项目,更建议获得存根服务。

在本文中,我们将描述如何使用虚拟化服务来实现存根服务。获取虚拟存根服务可以使存根与环境的其他部分隔离。此外,虚拟存根服务可以在以下情况下通过网络迁移存根服务:

各部门需要共享存根,以便他们可以在子系统开发过程中协作并使用相同的参考。
在测试(例如性能测试)期间需要改进存根服务基础设施(例如计算负载和带宽)。
可以使用虚拟化层来创建虚拟存根服务。我们将使用基于 Docker 的虚拟化,因为 Docker 可以在隔离的上下文中执行存根,仅重现所需的功能。

基于 Docker 的存根服务
Docker提供了轻松设置存根服务并具有高可靠性的可能性。正如我们在之前的文章中所描述的,在 Docker 中可以立即重现先前配置的行为。此外,虚拟化层创建了一个隔离,将存根接口作为外部服务执行。

现在是时候通过一些示例来教我们如何做到这一点了。我将介绍两个容器,以及每个容器的一个特定于存根的服务接口。所提出的示例是我自己的:它们使用自我分配的需求,与商业情况没有任何关联。

SUT:大数据,Stub:基于S3的数据源(示例1)
在本例中,我们需要为基于生成连续数据的S3存储桶的数据源设置存根。该数据可以根据速度、种类和数量来表征。此存根的潜在 SUT 目标是大数据应用程序。

我们对此示例存根的测试要求是:

存根生成定义的 kB 大小的随机字符作为 S3 对象
存根定期上传新的 S3 对象
存根将生成的 S3 对象发送到指定的存储桶
通过分析这些需求,我们可以提取添加到存根实现中的参数,以在启动时自定义存根行为:

kbSize - 生成的每个对象的 kB 大小
sheetAtMinute - 每次上传多少个对象的指示
bucket - 描述目标bucket名称

10-21 05:57