跳到主要内容

Stub Runner Core

DeepSeek V3 中英对照 Stub Runner Core

stub runner 核心运行为服务协作者准备的存根。将存根视为服务的契约,可以让你将 stub-runner 用作消费者驱动契约的一种实现。

Stub Runner 允许您自动下载所提供依赖项的存根(或从类路径中选择存根),为它们启动 WireMock 服务器,并使用适当的存根定义进行配置。对于消息传递,定义了特殊的存根路由。

检索存根​

你可以从以下选项中选择获取存根:

  • 基于 Aether 的解决方案,可从 Artifactory 或 Nexus 下载包含存根的 JAR 文件

  • 类路径扫描解决方案,通过模式匹配在类路径中搜索以获取存根

  • 编写自定义的 org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder 实现,以获得完全定制化的能力

后一个示例在自定义存根运行器部分有详细描述。

下载存根​

你可以通过 stubsMode 开关来控制存根的下载方式。它从 StubRunnerProperties.StubsMode 枚举中选取值。你可以使用以下选项:

  • StubRunnerProperties.StubsMode.CLASSPATH (默认值): 从类路径中选取存根

  • StubRunnerProperties.StubsMode.LOCAL: 从本地存储中选取存根 (例如,.m2)

  • StubRunnerProperties.StubsMode.REMOTE: 从远程位置选取存根

以下示例从本地位置选取存根:

@AutoConfigureStubRunner(repositoryRoot="https://foo.bar", ids = "com.example:beer-api-producer:+:stubs:8095", stubsMode = StubRunnerProperties.StubsMode.LOCAL)

类路径扫描​

如果你将 stubsMode 属性设置为 StubRunnerProperties.StubsMode.CLASSPATH(或者不设置任何值,因为 CLASSPATH 是默认值),则会扫描类路径。考虑以下示例:

@AutoConfigureStubRunner(ids = {
"com.example:beer-api-producer:+:stubs:8095",
"com.example.foo:bar:1.0.0:superstubs:8096"
})

你可以将依赖项添加到你的类路径中,如下所示:

<dependency>
<groupId>com.example</groupId>
<artifactId>beer-api-producer-restdocs</artifactId>
<classifier>stubs</classifier>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.example.thing1</groupId>
<artifactId>thing2</artifactId>
<classifier>superstubs</classifier>
<version>1.0.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
testCompile("com.example:beer-api-producer-restdocs:0.0.1-SNAPSHOT:stubs") {
transitive = false
}
testCompile("com.example.thing1:thing2:1.0.0:superstubs") {
transitive = false
}

随后,你的类路径中指定的位置会被扫描。对于 com.example:beer-api-producer-restdocs,会扫描以下位置:

  • /META-INF/com.example/beer-api-producer-restdocs/*/.*

  • /contracts/com.example/beer-api-producer-restdocs/*/.*

  • /mappings/com.example/beer-api-producer-restdocs/*/.*

对于 com.example.thing1:thing2,会扫描以下位置:

  • /META-INF/com.example.thing1/thing2/*/.*

  • /contracts/com.example.thing1/thing2/*/.*

  • /mappings/com.example.thing1/thing2/*/.*

提示

在打包生产者存根时,你必须明确提供 group 和 artifact ID。

为了实现正确的存根打包,生产者将按如下方式设置合约:

└── src
└── test
└── resources
└── contracts
   └── com.example
      └── beer-api-producer-restdocs
      └── nested
      └── contract3.groovy

通过使用 Maven assembly 插件 或 Gradle Jar 任务,你需要在你的存根 jar 中创建以下结构:

└── META-INF
└── com.example
└── beer-api-producer-restdocs
└── 2.0.0
├── contracts
│   └── nested
   │ └── contract2.groovy
   └── mappings
   └── mapping.json

通过保持这种结构,类路径会被扫描,您可以在无需下载构件的情况下利用消息传递或HTTP存根。

配置 HTTP 服务端存根​

Stub Runner 引入了 HttpServerStub 的概念,它抽象了 HTTP 服务器的底层具体实现(例如,WireMock 就是其中一种实现)。有时,您需要对存根服务器执行一些额外的调整(这些调整针对给定的具体实现)。为此,Stub Runner 提供了 httpServerStubConfigurer 属性,该属性在注解和 JUnit 规则中可用,并且可以通过系统属性访问,您可以在其中提供 org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer 接口的自定义实现。这些实现可以修改给定 HTTP 服务器存根的配置文件。

Spring Cloud Contract Stub Runner 提供了一个可扩展的实现,用于 WireMock:org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer。在 configure 方法中,你可以为给定的存根提供自定义配置。一个使用场景可能是为给定的构件 ID 在 HTTPS 端口上启动 WireMock。以下示例展示了如何实现:

示例 1. WireMockHttpServerStubConfigurer 实现

@CompileStatic
static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {

private static final Log log = LogFactory.getLog(HttpsForFraudDetection)

@Override
WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
int httpsPort = TestSocketUtils.findAvailableTcpPort()
log.info("Will set HTTPs port [" + httpsPort + "] for fraud detection server")
return httpStubConfiguration
.httpsPort(httpsPort)
}
return httpStubConfiguration
}
}

然后,你可以使用 @AutoConfigureStubRunner 注解来复用它,如下所示:

@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
httpServerStubConfigurer = HttpsForFraudDetection)

每当发现HTTPS端口时,它都会优先于HTTP端口。

运行存根​

本节介绍如何运行存根。包含以下主题:

HTTP 存根​

存根在JSON文档中定义,其语法在WireMock文档中定义。

以下示例以 JSON 格式定义了一个存根:

{
"request": {
"method": "GET",
"url": "/ping"
},
"response": {
"status": 200,
"body": "pong",
"headers": {
"Content-Type": "text/plain"
}
}
}

查看已注册的映射​

每个被存根化的协作者都会在 __/admin/ 端点下公开一个已定义映射的列表。

你也可以使用 mappingsOutputFolder 属性将映射关系转储到文件中。对于基于注解的方法,示例如下:

@AutoConfigureStubRunner(ids="a.b.c:loanIssuance,a.b.c:fraudDetectionServer",
mappingsOutputFolder = "target/outputmappings/")

对于JUnit方法,它类似于以下示例:

@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
.repoRoot("https://some_url")
.downloadStub("a.b.c", "loanIssuance")
.downloadStub("a.b.c:fraudDetectionServer")
.withMappingsOutputFolder("target/outputmappings")

然后,如果你查看 target/outputmappings 文件夹,你会看到以下结构;

.
├── fraudDetectionServer_13705
└── loanIssuance_12255

这意味着有两个存根被注册。fraudDetectionServer 注册在端口 13705,而 loanIssuance 注册在端口 12255。如果我们查看其中一个文件,我们会看到(对于 WireMock)给定服务器可用的映射:

[{
"id" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7",
"request" : {
"url" : "/name",
"method" : "GET"
},
"response" : {
"status" : 200,
"body" : "fraudDetectionServer"
},
"uuid" : "f9152eb9-bf77-4c38-8289-90be7d10d0d7"
},
...
]

消息存根​

根据提供的 Stub Runner 依赖项和 DSL,消息路由会自动设置。