跳到主要内容

使用外部仓库中的合约实现消费者驱动契约

DeepSeek V3 中英对照 Consumer Driven Contracts with Contracts in an External Repository

在此流程中,我们执行消费者驱动契约测试。契约定义存储在单独的代码仓库中。

前提条件​

要使用外部仓库中的消费者驱动契约,你需要设置一个git仓库,该仓库:

  • 包含每个生产者的所有合约定义。

  • 可以将合约定义打包成JAR文件。

  • 对于每个合约生产者,都提供了一种方式(例如,pom.xml),通过Spring Cloud Contract插件(SCC插件)在本地安装存根。

更多信息,请参阅操作指南部分,我们在其中描述了如何设置此类仓库。有关此类项目的示例,请参见此示例。

你还需要配置了 Spring Cloud Contract Stub Runner 的消费者端代码。相关示例项目可参考此示例。同时,你还需要配置了 Spring Cloud Contract 及其插件的生产者端代码。相关示例项目可参考此示例。存根存储库使用 Nexus 或 Artifactory。

从高层次来看,流程如下:

  1. 消费者使用来自独立代码库的契约定义进行开发。

  2. 消费者完成工作后,会在消费者端创建一个包含可运行代码的分支,并向存放契约定义的独立代码库发起拉取请求。

  3. 生产者接手针对存放契约定义的独立代码库的拉取请求,并在本地安装包含所有契约的 JAR 包。

  4. 生产者根据本地存储的 JAR 包生成测试,并编写缺失的实现以使测试通过。

  5. 生产者完成工作后,将针对存放契约定义的代码库的拉取请求合并。

  6. 在 CI 工具构建包含契约定义的代码库,并将包含契约定义的 JAR 包上传至 Nexus 或 Artifactory 后,生产者可以合并其分支。

  7. 最后,消费者可以切换到在线工作模式,从远程位置获取生产者的存根,并将分支合并到主分支。

消费者流程​

消费者:

  1. 编写一个向生产者发送请求的测试。

    由于没有服务器存在,测试失败。

  2. 克隆包含契约定义的代码仓库。

  3. 将需求设置为文件夹下的契约,以消费者名称作为生产者的子文件夹。

    例如,对于名为 producer 的生产者和名为 consumer 的消费者,契约将存储在 src/main/resources/contracts/producer/consumer/ 下。

  4. 一旦定义了契约,将生产者存根安装到本地存储,如下例所示:

    $ cd src/main/resource/contracts/producer
    $ ./mvnw clean install
  5. 在消费者测试中设置 Spring Cloud Contract (SCC) Stub Runner,以:

    • 从本地存储获取生产者存根。

    • 在按消费者存根模式下工作(这启用了消费者驱动契约模式)。

      SCC Stub Runner:

    • 获取生产者存根。

    • 使用生产者存根运行一个内存中的 HTTP 服务器存根。现在你的测试与 HTTP 服务器存根通信,并且你的测试通过。

    • 向包含契约定义的代码仓库创建一个拉取请求,其中包含生产者的新契约。

    • 分支你的消费者代码,直到生产者团队合并了他们的代码。

以下UML图展示了消费者流程:

flow-overview-consumer-cdc-external-consumer

生产者流程​

生产者:

  1. 接管包含合约定义仓库的拉取请求。你可以通过命令行操作,如下所示:

    $ git checkout -b the_branch_with_pull_request master
    git pull https://github.com/user_id/project_name.git the_branch_with_pull_request
  2. 安装合约定义,如下所示:

    $ ./mvnw clean install
  3. 设置插件以从 JAR 中获取合约定义,而不是从 src/test/resources/contracts 中获取,如下所示:

    Maven

    <plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
    <!-- 我们希望使用具有以下坐标的包含合约的 JAR -->
    <contractDependency>
    <groupId>com.example</groupId>
    <artifactId>beer-contracts</artifactId>
    </contractDependency>
    <!-- 包含合约的 JAR 应从本地 Maven 仓库获取 -->
    <contractsMode>LOCAL</contractsMode>
    <!-- ... 其他配置 -->
    </configuration>
    </plugin>

    Gradle

    contracts {
    // 我们希望使用具有以下坐标的包含合约的 JAR
    // group id `com.example`, artifact id `beer-contracts`, 最新版本且无分类器
    contractDependency {
    stringNotation = 'com.example:beer-contracts:+:'
    }
    // 包含合约的 JAR 应从本地 Maven 仓库获取
    contractsMode = "LOCAL"
    // 其他配置
    }
  4. 运行构建以生成测试和存根,如下所示:

    Maven

    ./mvnw clean install

    Gradle

    ./gradlew clean build
  5. 编写缺失的实现,以使测试通过。

  6. 将拉取请求合并到包含合约定义的仓库中,如下所示:

    $ git commit -am "Finished the implementation to make the contract tests pass"
    $ git checkout master
    $ git merge --no-ff the_branch_with_pull_request
    $ git push origin master

    CI 系统会构建包含合约定义的项目,并将包含合约定义的 JAR 上传到 Nexus 或 Artifactory。

  7. 切换到远程工作模式。

  8. 设置插件,使合约定义不再从本地存储获取,而是从远程位置获取,如下所示:

    Maven

    <plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
    <!-- 我们希望使用具有以下坐标的包含合约的 JAR -->
    <contractDependency>
    <groupId>com.example</groupId>
    <artifactId>beer-contracts</artifactId>
    </contractDependency>
    <!-- 包含合约的 JAR 应从远程位置获取 -->
    <contractsMode>REMOTE</contractsMode>
    <!-- ... 其他配置 -->
    </configuration>
    </plugin>

    Gradle

    contracts {
    // 我们希望使用具有以下坐标的包含合约的 JAR
    // group id `com.example`, artifact id `beer-contracts`, 最新版本且无分类器
    contractDependency {
    stringNotation = 'com.example:beer-contracts:+:'
    }
    // 包含合约的 JAR 应从远程位置获取
    contractsMode = "REMOTE"
    // 其他配置
    }
  9. 将生产者代码与新的实现合并。

  10. CI 系统:

  • 构建项目。

  • 生成测试、存根以及存根 JAR。

  • 将包含应用程序和存根的构件上传到 Nexus 或 Artifactory。

下面的UML图展示了生产者进程:

flow-overview-consumer-cdc-external-producer