极狐 GitLab

契约测试

契约测试由两部分组成:消费者测试和提供者测试。一个简单的消费者和提供者关系示例是前端和后端之间的关系。前端是消费者,后端是提供者。前端消费后端提供的 API。测试有助于确保双方遵循约定的契约,任何偏离契约的行为都会引发有意义的对话,以防止破坏性更改悄悄混入。

消费者测试类似于单元测试,每个 spec 定义一个请求和预期的模拟响应,然后根据这些定义创建契约。提供者测试类似于集成测试——每个 spec 获取契约中定义的请求,针对实际服务运行它,并将响应与契约进行匹配以验证它。

你可以在以下位置查看现有的契约测试:

目前契约本身存储在 /spec/contracts/contracts 中。计划使用托管在 AWS 或其他类似服务上的 PactBroker

编写测试#

运行消费者测试#

在运行消费者测试之前,进入 spec/contracts/consumer 并运行 npm install。要运行所有消费者测试,只需运行 npm run jest:contract -- /specs。否则,要运行特定的测试文件,将 /specs 替换为特定的测试文件名。运行消费者测试将创建提供者测试用于验证实际 API 行为的契约。

你也可以从项目根目录使用命令 yarn jest:contract 运行测试。

运行提供者测试#

在运行提供者测试之前,确保你的 GDK(极狐GitLab 开发工具包)已完全设置并正在运行。你可以按照 GDK 仓库 中详述的设置说明进行操作。要运行提供者测试,你可以使用可在 ./lib/tasks/contracts 中找到的 Rake 任务。要获取与提供者测试相关的所有 Rake 任务列表,请运行 bundle exec rake -T contracts。例如:

shell
$ bundle exec rake -T contracts rake contracts:merge_requests:pact:verify:diffs_batch # Verify provider against the consumer pacts for diffs_batch rake contracts:merge_requests:pact:verify:diffs_metadata # Verify provider against the consumer pacts for diffs_metadata rake contracts:merge_requests:pact:verify:discussions # Verify provider against the consumer pacts for discussions rake contracts:merge_requests:test:merge_requests[contract_merge_requests] # Run all merge request contract tests

在 Pact Broker 中验证契约#

默认情况下,Rake 任务将验证本地存储的契约。为了验证发布到 Pact Broker 的契约,我们需要将 PACT_BROKER 环境变量设置为 true,并将 QA_PACT_BROKER_HOST 设置为 Pact Broker 的 URL。这里需要指出的是,提供者测试的文件路径和文件名用于在 Pact Broker 中查找契约,这就是为什么确保遵循 提供者测试命名约定 很重要的原因。

将契约发布到 Pact Broker#

通过设置 QA_PACT_BROKER_HOST 环境变量并运行 publish-contracts.sh 脚本,可以将消费者测试生成的契约发布到托管的 Pact Broker。

测试套件文件夹结构和命名约定#

为了保持消费者和提供者测试套件的组织性和可维护性,测试的组织以及消费者和提供者的命名一致性非常重要。因此,遵循以下约定非常重要。

测试套件文件夹结构#

为测试套件拥有一个组织合理且合理的文件夹结构,可以在审查、调试或引入测试时更容易找到相关文件。

消费者测试#

消费者测试根据应用程序中的不同页面进行分组。每个文件包含页面中的各种请求类型。因此,消费者测试文件使用 Rails 标准中引用页面的方式进行命名。例如,项目流水线页面将是 Project::Pipelines#index 页面,因此等效的消费者测试将位于 consumer/specs/project/pipelines/index.spec.js

在定义测试生成的契约的输出位置时,我们希望遵循相同的文件结构,在此示例中为 contracts/project/pipelines/。这也是 consumer/resourcesconsumer/fixtures 中的结构。

文件夹的命名也必须复数化,以匹配它们在 Rails 命名标准中的调用方式。

提供者测试#

提供者测试的分组方式与我们的控制器类似。这些测试中的每一个都包含针对 API 端点的各种测试。例如,获取项目流水线列表的 API 端点将位于 provider/pact_helpers/project/pipelines/get_list_project_pipelines_helper.rb。提供者状态根据应用程序中的不同页面进行分组,类似于消费者测试。

命名约定#

在编写消费者和提供者测试时,有些部分需要为消费者和提供者命名。由于 Pact 对这些命名没有限制,因此命名约定对于在调试期间轻松确定涉及哪些消费者和提供者测试非常重要。Pact 还使用消费者和提供者名称以 #{consumer_name}-#{provider_name} 格式创建本地存储的契约文件名。

消费者命名#

文件夹结构部分 所述,消费者测试根据应用程序中的不同页面进行分组。因此,消费者名称应使用 Rails 标准遵循相同的命名格式。例如,Project::Pipelines#index 的消费者测试将位于 project 文件夹下,并将消费者名称命名为 Pipelines#index

提供者命名#

这些是向消费者提供数据的 API 端点,因此它们根据所属的 API 端点进行命名。请注意,命名以 HTTP 请求方法开头,其余部分尽可能具有描述性。例如,如果我们正在为 GET /groups/:id/projects 端点编写测试,我们不想将其命名为 "GET projects endpoint",因为还有一个 GET /projects 端点,它也获取用户在极狐GitLab 中可访问的所有项目列表。

要选择合适的名称,我们可以先查看我们的 API 文档,并按照其中的命名方式进行命名,同时确保名称保持句子大小写。因此,GET /groups/:id/projects 将被称为 GET list a group's projects,测试文件名为 get_list_a_groups_projects_helper.rbGET /projects 将被称为 GET list all projects,测试文件名为 get_list_all_projects_helper.rb

在某些情况下,被测试的提供者可能没有文档记录,因此在这些情况下,回退到以 HTTP 请求方法开头,后跟尽可能具有描述性的名称,以确保容易判断提供者的用途。

约定总结#

测试文件夹结构命名约定
消费者测试遵循 Rails 引用标准。例如,Project::Pipelines#index 将是 consumer/specs/project/pipelines/index.spec.js遵循 Rails 命名标准。例如,Project::Pipelines#indexproject 文件夹中将是 Pipelines#index
提供者测试像 Rails 控制器一样分组。例如,GET list project pipelines API 端点 将是 provider/pact_helpers/project/pipelines/get_list_project_pipelines_helper.rb遵循句子大小写的 API 文档命名方案。例如,GET /projects/:id/pipelines 将被称为 GET list project pipelines