【合约测试】使用Postman进行消费者驱动的合同测试

Chinese, Simplified

实施消费者驱动的合同测试是维护不断增长的微服务堆栈的好方法。 它使团队在定期完成时不会因API差异而受阻。 这是Postman如何帮助您做得更好。

 

API行为通常在文档页面中描述,该页面列出了可用的端点,请求数据结构和预期的响应数据结构,以及示例查询和响应。然后,构建使用这些API的系统的人员将使用这些文档。

但是,单独编写的文档不会保护API的使用者免受API的更改。 API生产者可能需要更改响应数据结构或完全重命名端点以满足业务需求。

然后,合并这些更改的责任落在那些必须不断检查文档以进行任何更改的API的消费者身上。该模型不能很好地扩展。消费者经常会遇到意想不到的错误,因为他们期待的反应已经发生了变化。

这是让消费者对API合同断言变得有用的地方。这些API的消费者可以通过让生产者知道他们想要从API获得哪些数据来设置期望,而不是让API生成者自己构建规范。

然后,API设计将转变为消费者需要的内容与提供商可以提供的内容之间的协商。

使API合约显式且可执行


Postman在今年早些时候进行了一项调查,结果显示大多数业务API都是内部的。这些是在组织内构建服务的团队,这些团队聚集在一起构建面向用户的更大产品。在这种情况下,确保消费者的期望与API提供的数据之间没有差异,这成为组织工作流程的重要组成部分。拥有明确,可共享和可执行的合同可以防止这种混乱和挫折。

生产者可以通过使用市场上任何流行的工具(如RAML,API Blueprint,OpenAPI,Pact或Postman Collections)为其API创建规范,而不是在静态页面中记录API行为。最后两个,Pact和Postman让您实现消费者驱动的合同作为一流的概念。 Pact进一步专注于合同测试,而Postman生态系统除此之外还包含更多功能。

所有这些格式都允许您指定有关API行为的详细信息。它们允许您通过端点名称,描述,数据类型以及请求和响应的数据结构来传达API的意图。他们还支持向每个端点添加示例。

一旦获得这些格式的规范,就可以运行生成测试代码的工具,或使用规范中描述的端点结构直接将请求发送到给定服务。您获得的灵活程度因您使用的工具集而异。

这些规范构成了服务合同的来源 - 生产者提供的内容与消费者期望的内容之间的协议。每个工具集的基本价值在于,它们使您的API结构对于协作构建服务以及服务的使用者而言是明确的。

针对多个消费者测试合同


如果您是消费者,拥有这样的规范便可让您确切地知道要从API中获取哪些数据。您可以编写测试来设置期望并断言您的服务将使用的数据。这种方法有两个主要好处:

  • 只要规范发生变化,您就可以运行测试套件,并主动响应API规范中的更改,并且,
  • 您可以作为消费者参与API的设计过程,并在合同正式化之前让您的需求得到了解。

在消费者驱动的合同测试中,合同由消费者明确编写和管理。如果生产者需要对其服务进行一些更改,例如实施新功能,生产者只需查看哪些消费者的合同测试失败就可以了解他们打破了哪些消费者。这使得API提供商不必担心每次他们对服务进行一些更改时都会意外破坏消费者应用或服务。

独立服务测试


这减少了执行端到端服务测试的需要。如果所有合同测试都通过,API生产商可以合理地确定他们的服务在与其他服务集成时按预期执行。对于在微服务环境中进行端到端测试的复杂性而言,这是一个巨大的缓解。

对于API的每次更改,端到端测试都是昂贵且繁琐的。生产者和消费者可以按照自己的步调移动,拥有自己的路线图并不断部署他们的变化。消费者团队只有在合同测试失败时才需要担心。将此与从规范自动生成的更新文档相结合,可以快速检测故障,而无需构建运行端到端测试所需的复杂设置。

将Postman用于消费者驱动的合同


Postman拥有您开始在组织中实施合同测试所需的所有工具。 Postman Collections是API的可执行规范。您可以使用Postman应用程序在本地计算机上运行集合,在命令行上使用newman运行CI系统,使用监视器在云中运行集合。在任何一种情况下,集合中的请求都是按顺序执行的。

此外,您可以使用预请求脚本为请求添加动态行为,并通过测试对响应进行断言。有关在Postman中从手动过渡到自动API测试的文章将向您介绍这些步骤的详细信息。

将所有这些与Postman中的Workspace相结合,您就可以为整个团队准备好可执行,共享和协作的合同集合。您无需与团队成员手动共享这些详细信息。

让我向您介绍一个示例用例,了解这些用例如何实现以消费者为导向的合同。

示例用例:简单日志检索服务


假设我们需要构建一个假设的服务,该服务返回来自某个集中式日志存储的日志条目列表。此服务仅公开一个端点(为简单起见),它返回最新的5个日志条目,其中包含创建条目的服务的名称,条目的时间戳以及描述该条目的描述字符串。

端点位于/ api / v1 / logs。向此端点发送GET请求应该返回此结构中的JSON数据:

{
  "count": Number,
  "entries": Array[Object]
}


entries数组将包含每个日志条目的对象。他们的数据结构如下所示:

{
  "serviceName": String,
  "timestamp": Number,
  "description": String
}

蓝图


首先,我们创建一个蓝图集合。蓝图集合规定了API结构。这是由服务的生产者创建的。

您可以在此处访问此示例的蓝图集合。


示例蓝图集合
然后,我们为请求添加示例。我已经添加了一个例子。示例允许此类蓝图集合描述响应数据。它们出现在Postman生成的文档中。以下是此服务的默认输出的响应数据示例:

{
  "count": 5,
  "entries": [
    {
      "serviceName": "foo",
      "timestamp": 1540206226229,
      "description": "Received foo request from user 100"
    },
    {
      "serviceName": "bar",
      "timestamp": 1540206226121,
      "description": "Sent email to user 99"
    },
    {
      "serviceName": "foo",
      "timestamp": 154020622502,
      "description": "Received foo request from user 10"
    },
    {
      "serviceName": "baz",
      "timestamp": 1540206223230,
      "description": "Activated user 101"
    },
    {
      "serviceName": "bar",
      "timestamp": 1540206222126,
      "description": "Error sending email to user 10"
    }
  ]
}


每个示例都有一个名称和特定的请求路径。这就是它在Postman应用程序中的外观:


添加示例以示例蓝图集合的请求
有了这些,Postman会自动为蓝图生成基于Web的文档。以下是已发布文档的截图。


由Postman从示例蓝图集合生成的已发布文档
作为创建此集合的工作空间的所有成员可以查看文档并访问集合,使其成为与其他成员协作的绝佳方式。然后,服务所有者可以基于此集合在Postman中创建模拟服务器。请求中添加的示例将作为模拟服务器响应的一部分发送。

在Postman中创建模拟服务器后,您可以在Postman为您生成的模拟服务器URL之后使用相同的端点向模拟服务发出请求。因此,向https:// <mock-server-id> .pstmn.io / api / v1 / logs发出请求将返回以下响应:


从样本集合创建的模拟服务器返回响应

写合同集合


服务的消费者可以根据蓝图和模拟来构建合同集合。 Postman测试允许您在响应的每个方面断言 - 包括响应标头,正文和响应时间。 因此,合同可以利用所有这些并构建可靠的测试。

对于此示例,我们假设此服务只有一个使用者。 为了简单起见,我们的契约集合示例也将有一个请求,它将仅在响应数据结构上断言。 现实世界的合同将断言数据结构以及响应中收到的数据。

以下是合同集合可用于测试上述数据结构的测试脚本。 它使用tv4库,它作为Postman Sandbox的一部分提供:

// Define the schema expected in response
var responseSchema = {
    "type": "object",
    "properties": {
        "count": {
            "type": "number"
        },
        "entries": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "serverName": {
                        "type": "string"
                    },
                    "timestamp": {
                        "type": "number"
                    },
                    "description": {
                        "type": "string"
                    }
                }
            }
        }
    }
}
// Get response data as JSON
var jsonData = pm.response.json();
// Test for response data structure
pm.test('Ensure expected response structure', function () {
    var validation = tv4.validate(jsonData, responseSchema);
    pm.expect(validation).to.be.true;
});

 

合同集合在此发布。您可以使用该页面上的“Run in Postman”按钮在Postman应用程序中加载该集合,并浏览与该请求相关的测试。

请注意在合同集合中使用{{url}}变量占位符。当服务处于早期阶段时,消费者可以使用模拟服务器URL来发出请求。构建服务后,可以将环境变量切换为指向服务的托管实例。这样,消费者应用程序或服务的开发可以并行发生,而不会被阻止以构建上游服务。

持续测试


合同需要不断测试,以确保它们随着时间的推移有效。有两种方法可以实现。

如果您有一个现有的持续集成系统:您可以从Postman导出集合文件和环境,并使用newman从命令行运行它们。有关为Jenkins和Travis CI设置连续构建的步骤,请参阅newman的文档。每当规范或新版本的上游服务发生更改时,都可以触发构建管道。

除此之外,您还可以使用Postman Monitors运行合同集合。监视器可以定期运行,使其成为一个很好的工具,可以长期了解合同中断情况。

阅读有关使用Postman持续测试API的更多信息。


组织合同测试


真实世界的测试有设置和拆卸阶段。合同测试也不例外。合同测试的一个常见用例是使用某些数据填充正在测试的系统,然后对其执行操作,最后删除这些测试数据。

在Postman中模拟这种模式的一种巧妙模式是将Setup文件夹作为集合中的第一个文件夹,将Teardown文件夹作为集合的最后一个文件夹。然后,所有合同测试都将作为Setup和Teardown文件夹之间的文件夹。这将确保Postman始终在集合运行开始时在Setup文件夹中运行请求,然后运行执行实际测试的请求,并以运行Teardown文件夹中的所有请求结束。

在编写内部合同时,我们会大量使用这种模式。

这有助于通过抽象出第一个和最后一个文件夹中的重复任务来巧妙地分组和组织测试。 理想情况下,API生产者应提供包含Setup和Teardown请求的集合。 消费者可以创建该集合的副本并添加他们的合同测试。

合同测试的复杂性取决于您的业务案例。 编写消费者驱动的合同测试的一个额外好处是,通过查看服务所拥有的消费者合同集合的数量,您可以轻松发现服务变得太大或具有太多依赖性。

总体而言,消费者驱动的合同有助于保持表面区域以测试微服务并将变更协商到可控大小。

快乐的测试!

参考

 

原文:https://medium.com/better-practices/consumer-driven-contract-testing-using-postman-f3580dba5370

讨论: 加入知识星球【首席架构师圈】

 

 

SEO Title
Consumer-driven Contract Testing using Postman