【问题标题】:Automated tests on contracts between microservices?对微服务之间的合约进行自动化测试?
【发布时间】:2018-01-26 19:39:44
【问题描述】:

假设我们有一个 CreditCardService 微服务,它依赖于 ThreeDSecureService 微服务,使用 JSON 进行通信。

ThreeDSecureService 的 API(甚至实现)中的微小更改可能会默默地破坏 CreditCardService(和其他潜在客户)。所以,我们想要自动化测试。

我看到了两种有缺陷的方法,想知道如何改进。

  1. ThreeDSecureService.Tests 中的集成测试。

ThreeDSecureService 附带的测试项目可以使用固定的 JSON 输入进行集成测试。伪造任何依赖项,它可以对该输入运行一个完整的调用,确认服务吞下了输入。

这里的问题是,如果有人没有意识到他们的更改会如何破坏客户端,他们几乎同样可能会“修复”测试以匹配他们的更改。

  1. CreditCardService.Tests 中的集成测试。

客户端 是真正想要测试有关 ThreeDSecureService 预期输入的断言的客户端。但是,这将要求客户端解决方案包含 ThreeDSecureService 项目以及它所依赖的任何项目。这将抵消我们从使用微服务中获得的许多优势!

我们如何从客户端做出断言(保护依赖关系)而不破坏我们使用微服务获得的松散耦合?

【问题讨论】:

  • 您不能简单地让您的集成测试项目了解它们(通过引用或以某种方式启动它们)吗?这两个服务不需要相互了解,但我认为在引用它们的测试项目中没有任何害处。
  • 在这里阅读我的答案:stackoverflow.com/a/45177810/569662。 OP 有一个关于如何管理服务依赖项的类似问题。
  • @kkirk 但是,当您处理客户端项目时,您需要运行常规测试。所以您需要将集成测试项目包含在客户端解决方案中,不是吗?如果我们可以引用依赖项的 DLL 就好了……但是我们如何保持它是最新的,即最新的和构建的?
  • @Timo 我试图在评论中回复,但评论总是太长,所以我会发布一个答案。

标签: c# api integration-testing microservices contract


【解决方案1】:

为避免破坏集成,请使用公共合同。例如,RAML。描述特定服务的客户端将获取和传递的模型,描述动作和参数。在这种情况下,没有人依赖特定的服务或实现,双方只需要测试他们与合约的通信即可。

额外的安全措施是将您的合同发布为 dll。在这种情况下,服务的消费者会在一分钟内注意到变化。如果他们有单元测试,他们可能会更早地显示任何问题。

作为保持解耦的主要规则:不要参考实现,而是参考合同。

【讨论】:

    【解决方案2】:

    我希望我已经理解了您的问题,但如果不是,那么以下内容至少对您的思考有所帮助。

    我理解您的问题的方式是一个非常实用的问题,即“我如何组织解决方案和项目以最大程度地降低开发人员违反服务合同的风险而不了解它对该服务的消费者的影响? "

    在理想世界中,开发人员不会这样做。如果他们对服务进行重大更改,他们就知道他们已经完成了,这是一个新版本。话虽如此,我明白你的意思 - 很高兴有某种保护措施来防止这种人为错误,因为开发人员在大多数情况下都是完美的。

    如果您在一个环境中工作,您正在创建其他团队所依赖的微服务,反之亦然,那么就无法绕过有纪律和结构化的方法,即适当的治理。一个反映生产的完整测试环境,所有服务都在其中运行,并且您可以测试您的服务与它所依赖的服务的良好集成,这也没有什么坏处。

    如果您可以控制需要相互通信的所有服务,那么(至少在我看来)没有理由不应该拥有一个包含所有服务项目以及您的集成测试项目启动它需要的所有服务,并检查它们之间的集成是否按预期工作。

    您的个人微服务不应该知道任何关于外部世界的信息,除了合约/接口,您应该有单元测试来单独测试每个微服务,模拟依赖关系。

    如果一个解决方案变得太大,您可以将其分解为更小的部分,为每个服务(包括该服务及其最近的邻居)提供一个解决方案。在您的示例中,这可能是一个包含 ThreeDSecureService、CreditCardService 和 CreditCardService.IntegrationTests(测试 CreditCardService 进而调用 ThreeDSecureService)的解决方案。 这样,当开发人员在 ThreeDSecureService 上工作时,集成测试将让开发人员知道他/她已经破坏了集成。 当然,这仍然需要开发人员记住实际运行集成测试。

    在我看来,最终目标是在您的构建流程中加入一个入口,以确保开发人员无法发布可能导致集成测试失败的更改,同时自动部署。这将确保基本的集成错误不会进入生产环境。

    【讨论】:

    • 我喜欢阅读这篇文章。 :) 您如何建议微服务“了解”合同?目前,他们有自己的序列化模型,假设他们调用的服务仍然遵守该合同。 我的目标是在这些合同发生变化时提前发出警告(这通常意味着有人搞砸了)。合同应该易于维护,并且在解决方案管理方面增加很少的开销。
    • 太好了,我很高兴它很有用。我建议在 NuGet 包或类似包中定义合同的接口,它是版本化的,以便您准确了解每个服务实现的合同。我将通过为每个服务定义一个单独的命名空间来处理服务的版本控制,即 CreditCardService.v1_0、CreditCardService.v1_1 等。您可以对合同 NuGet 包所依赖的单独 NuGet 包中的数据模型执行相同的操作。这样,当所有服务都在同一个版本的包上时,它们对每个数据模型的理解都是一样的。
    • 有趣的想法。我也在考虑类似的替代方案,例如仅使用合同引用 DLL,或者让所有内容都引用一个大型合同项目(填充接口)。我将不得不调查每种方法的优缺点。
    猜你喜欢
    • 2018-03-25
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多