如何进行微服务的API测试

作为构建复杂系统的架构,微服务在开发社区中获得了巨大的吸引力。虽然人们开始明白它并不是解决所有应用程序架构问题的灵丹妙药,但是分享与依赖关系和扩展相关的挑战的应用程序可以从中受益匪浅。

微服务的采用率正在上升,但与理解如何测试微服务相关的斗争也在增加。来自ThoughtWorks的Toby Clemson 在枚举您可能想要在微服务架构中使用的测试策略方面做得非常出色(请参阅他的文章,了解您可能想要创建的不同类型的测试),但主流知识如何构建和维护这些不同类型的测试仍处于起步阶段。

但是,在许多方面,测试微服务应用程序与测试使用任何其他架构构建的应用程序没有什么不同。微服务使用众所周知的技术,例如REST或队列,软件行业已经拥有完善的测试工具和最佳实践。微服务面临的独特挑战是构成应用程序的服务数量以及服务之间的依赖关系。此外,每个微服务仍然需要正常运行,即使它们所依赖的其他微服务不可用或响应不正确。

微服务在彼此交互时通常遵循两种模式:编排和反应(编排)。许多微服务使用组合的“混合”方法。在这篇文章中,我将提供一些策略来解决在为使用这些不同模式的微服务创建自动化测试时出现的一些挑战,重点关注单个微服务的测试(而不是整个应用程序的端到端测试) )。

测试Orchestrated微服务

使用业务流程的微服务将对外部服务或依赖项进行一次或多次显式调用。这些调用通常使用同步请求 – 响应流,并且通常会访问基于REST的服务。如果需要以特定顺序调用服务,则在收到对先前服务的调用的响应之前,不会调用后续服务。因为一个服务明确地调用另一个服务,所以它们紧密耦

在上面显示的示例中,为Portfolio微服务创建和执行测试具有挑战性,因为Portfolio微服务依赖于Accounts和Quotes微服务,这些微服务需要与Portfolio微服务一起部署在测试环境中。Quotes服务依赖于第三方服务来检索实时股票价格,并且该服务返回的数据总是在变化。

依靠不同团队开发的第三方服务或服务极大地增加了测试环境的复杂性。此外,需要测试Portfolio服务的任何意外行为,例如当Accounts和/或Quotes服务不可用,响应缓慢或响应意外数据时。能够使这些服务响应不同类型的意外行为以验证Portfolio微服务是否正确处理错误条件非常重要。​

服务虚拟化到救援!

您可以使用服务虚拟化  来模拟帐户和报价微服务的响应。通过服务虚拟化,您可以定义帐户和报价微服务的虚拟版本,并将它们与Portfolio微服务的实际实例一起部署。虚拟化微服务类似于虚拟化任何其他类型的服务或应用程序架构。它可能看起来像这样:

完成此操作后,可以独立于其两个依赖项测试Portfolio微服务。

下一个挑战是为不同的情况配置不同的环境,例如当Accounts和Quotes服务显示预期和意外行为时。假设团队希望在Accounts服务或Quotes服务响应缓慢或响应错误条件时测试Portfolio服务的行为方式。这可能需要运行至少5组不同的测试,每组测试具有不同的环境配置,考虑到响应时间慢,错误响应以及从属服务的正常和异常行为。

对于每次测试运行,在运行该配置的测试之前,需要将环境置于正确的配置中。在这个例子中,我们最终得到至少五个不同的测试运行,每个测试运行都有自己的环境配置。Parasoft的Continuous Testing Platform中的Environment Manager模块可以为您管理这些不同的环境配置:

此过程并非特定于微服务架构 – 一般而言,面向服务的体系结构中出现相同类型的问题,以及可能仅依赖于少数服务的单片应用程序。然而,在微服务架构中,依赖服务的数量显着增加。在具有数十或数百个服务的微服务环境中,为不同的测试场景创建,管理和以编程方式在不同环境配置之间切换的能力非常重要,并且可以显着减少时间和精力。

管理Orchestrated微服务中的API更改

随着团队不断发展他们的微服务,不可避免地会对服务进行API更改。API更改带来的一个关键问题是如何理解这些更改对服务使用者的影响。

当团队为他们正在构建的微服务修改API时,任何验证微服务的测试都需要根据API中的更改进行更新。相反,如果虚拟服务用于模拟依赖的微服务和用于其中一个依赖的微服务更改的API,则必须更新依赖微服务的虚拟服务以反映API中的更改。

许多团队使用OpenAPI,RAML或其他服务定义来描述其微服务的API。使用服务定义时,Parasoft SOAtestParasoft Virtualize中的Change Advisor模块 可以自动检测哪些API已更改,然后自动重构现有功能测试或虚拟服务,以使用API中的任何新字段和/或已删除字段更新它们。团队可以创建其服务定义的更新版本,并在进行更改之前使用Change Advisor了解更改对其测试和虚拟服务的影响。一旦进行了更改,Change Advisor就可以快速轻松地更新现有资产,以反映微服务中的变化。

测试反应性微服务

微服务架构的主要目标之一是创建独立的组件。因此,部署,扩展和更新服务将变得更加容易。但是,在使用业务流程模式时,并未完全实现此目标,因为各个微服务对其他微服务具有直接依赖性。解决此问题的方法是使用编排模式,也称为“反应”或“事件驱动”微服务。在这种模式中,微服务不直接相互引用。相反,他们将消息推送到其他微服务已订阅的事件流。

请参阅以下示例:

在这个例子中,假设已经指示投资组合服务添加股票头寸。它不是直接调用Accounts服务,而是向“Position Added”事件流发布事件。Accounts微服务已订阅该事件流,因此它获得通知。它会检查以确保用户的帐户中有足够的资金。如果是这样,它会减少用户帐户中的资金数量,并将事件发布到“帐户更新”事件流。如果用户在他们的帐户中没有足够的资金,则它可以将错误事件发布到不同的事件流(为了简化示例,未示出)。Portfolio微服务订阅了“帐户更新”事件流,当它看到Accounts微服务发布的事件时,

这种类型的体系结构中的异步通信引入了服务彼此高度分离的好处 – 每个服务的实例可以被替换,重新部署或扩展,而不需要其他微服务关注它们。权衡是事件的异步性质使得更难理解系统将如何执行以及事件流将是什么。根据生成的事件的顺序或种类,系统可能会以意想不到的方式运行。这被称为紧急行为,并且是编排的微服务的开发和测试中的固有挑战。

异步命令调用模式

有不同的异步消息传递模式  属于更广泛的事件驱动的微服务类别。当微服务需要使用异步操作进行编排时,使用异步命令调用模式 – 其中一个微服务需要异步调用另一个微服务,同时保证第二个微服务接收消息。在此模式中,通常使用队列交换消息。

RabbitMQ是微服务架构中用于实现此模式的通用框架。当一个微服务需要发布第二个微服务的事件来处理然后等待从该第二个微服务读取“回复”事件时,就会出现这种模式的特定化身。

考虑我们刚刚讨论的Portfolio示例,其中REST API调用告诉Portfolio微服务添加位置。Portfolio服务将事件发布到要添加的位置,以便处理Accounts微服务,然后等待Accounts服务将回复事件发布到Account Updated队列,以便REST API调用可以返回从该事件接收的数据。为此示例配置测试方案有两种不同的方法:

  1. 第一种方法是创建具有必要队列的环境,其中部署了Portfolio服务,但未部署Accounts服务。由于未部署Accounts服务,因此测试方案需要通过在适当的时间从Accounts服务发布预期事件来模拟Accounts服务的行为。Parasoft SOAtest测试场景将使用两个测试构建:一个执行Portfolio服务的REST API,另一个测试从Accounts服务发布事件。需要将测试配置为并发运行,以便在Portfolio服务正在侦听事件时,来自Accounts服务的事件发布。
  2. 不是通过使用测试来发布其事件来模拟Accounts服务,而是构建可重用的虚拟服务,该服务可以监听发布到Position Added队列的事件并将结果事件发布到Account Updated队列。然后,这个虚拟微服务可以在可能需要它的多个不同测试场景中重用。

第一种方法很简单,它是一种独立的测试资产,在测试基础架构上没有额外的外部依赖性。第二种方法是可重用的,是对系统真实行为的更接近的模拟。然而,第二种方法具有构建,部署和管理单独虚拟资产的成本。

异步命令调用模式的变体是一种微服务,它在队列中侦听传入事件,处理事件,然后在不同队列上发布后续事件,以便处理一个或多个其他微服务:

在此示例中,Invoice微服务是需要测试的服务。Payments服务将一个事件发布到Payment Processed RabbitMQ队列,以便Invoice服务获取。Invoice微服务从队列中读取事件,创建发票,然后将事件发布到Invoice Created队列,以指示Email微服务使用发票向客户发送电子邮件。要为Invoice微服务创建测试场景,可以配置包含两个RabbitMQ队列和部署的Invoice微服务的测试环境。可以构建Parasoft SOAtest测试场景,将付款处理的事件发布到Payment Processed队列。然后,该方案订阅“发票创建”队列,以验证发票服务响应是否发布了正确的发票创建事件。这是一个非常简单的测试场景,可以独立地测试Invoice服务。

事件Firehose模式

当不同的源产生大量需要通过公共集线器快速传递给不同消费者的事件时,使用事件firehose模式。在此模式中,消息通过主题交换(与通过队列交换消息的异步命令调用模式相反)。用于实现事件firehose模式的通用框架是Apache Kafka框架,它看起来像这样:

假设我们想要测试订阅Kafka主题的单个微服务,处理它接收的事件,然后将其结果发布到第二个Kafka主题。例如,像这样:

在此示例中,我们有一个预测微服务,订阅了一个天气数据主题,该主题从许多不同的来源收集了大量不同的天气数据。然后,它处理该数据以更新其预测模型,并将预测数据发布到预测数据主题。在这种情况下,我们需要验证Forecast服务是否将预期事件发布到一组特定的Weather Data事件的Forecast Data主题。

这可以通过配置具有两个Kafka主题和已部署的Forecast服务的测试环境来完成。测试场景首先将必要的事件发布到Weather Data主题,然后订阅Forecast Data主题以验证Forecast服务是否发布了正确的预测数据事件。需要构建多个不同的测试场景,以验证预测由微服务处理的事件的不同类型和顺序。

这是一个相对简单的测试场景。预测微服务与其他微服务分离的事实具有幸运的副作用,即预测服务的测试也与微服务分离。在这种情况下,您不需要使用虚拟服务设置复杂的环境 – 您只需创建发布事件的测试方案并验证是否在响应中创建了正确的事件。

配置测试环境

许多微服务团队采用持续集成/持续部署(CI / CD)流程来构建,测试和部署容器化微服务,以自动化流程并降低与部署更新相关的风险。

在此过程中,包含微服务的容器映像会自动创建并部署到测试环境中(通常由Kubernetes  或基于Kubernetes的分发管理,如OpenShift),其中微服务可以在推送到端到端之前进行验证。结束测试,最后投入生产。我建议阅读容器化微服务设计微服务的CI / CD :持续集成。这两篇文章都很好地描述了这种过程。

用于测试微服务的服务虚拟化

我们讨论过的一些测试模式依赖于依赖微服务使用虚拟服务。这些虚拟服务需要高度组件化并且易于部署,其原因与它们模拟的微服务是组件化的相同。要使服务虚拟化在这些环境中运行,您需要创建易于部署的容器化虚拟服务。

要创建容器化虚拟服务,您可以获取包含Parasoft Virtualize及其所有依赖项的基础映像,并将其与包含虚拟服务的所有虚拟资产配置的另一个映像分层。可以将虚拟服务的新映像作为容器部署到Docker / Kubernetes环境中,同时将容器用于所测试的微服务及其所有(虚拟化)依赖项。

结论

随着团队采用微服务,了解如何充分测试它们非常重要。我在这里讨论的消息模式和相关的测试模式并不新鲜,但随着微服务变得越来越普遍,越来越多的应用程序采用微服务范式,使用这些模式的需求也大大增加。

翻译来源:https://dzone.com/articles/how-to-approach-api-testing-for-microservices-1

赞赏


微信赞赏

支付宝赞赏