请使用 spring-cloud-contract 5.0.2 获取最新稳定版本!spring-doc.cadn.net.cn

Spring Cloud Contract WireMock

Spring Cloud Contract WireMock 模块允许您在 Spring Boot 应用程序中使用 WireMock。欲了解更多信息,请查看 Spring Cloud Contract 的存储库中的 示例子文件夹spring-doc.cadn.net.cn

如果您有一个使用 Tomcat 作为嵌入式服务器的 Spring Boot 应用程序(这是默认配置,即 spring-boot-starter-web),您可以将 spring-cloud-starter-contract-stub-runner 添加到类路径中,并将 @AutoConfigureWireMock 添加到您的测试中,以在测试中使用 WireMock。WireMock 作为一个模拟服务器运行,您可以通过 Java API 或通过将静态 JSON 声明作为测试的一部分来注册模拟行为。spring-doc.cadn.net.cn

要以不同端口启动存根服务器,请使用(例如)@AutoConfigureWireMock(port=9999)。若需随机端口,请将值设为 0。存根服务器端口可在测试应用上下文中通过 wiremock.server.port 属性进行绑定。使用 @AutoConfigureWireMock 可将类型为 WiremockConfiguration 的 Bean 添加至您的测试应用上下文,该 Bean 将在具有相同上下文的方法和类之间进行缓存。Spring 集成测试亦遵循相同规则。此外,您还可以将类型为 WireMockServer 的 Bean 注入到您的测试中。已注册的 WireMock 服务器会在每个测试类结束后重置。但若需在每个测试方法后重置它,请将 wiremock.reset-mappings-after-each-test 属性设为 truespring-doc.cadn.net.cn

自动注册存根

如果您使用 @AutoConfigureWireMock,它将从文件系统或类路径中注册 WireMock JSON 存根(默认情况下,从 file:src/test/resources/mappings 中读取)。您可以通过在注解中使用 stubs 属性来自定义位置,该属性可以是 Ant 风格的资源模式或目录。如果是目录,则会附加 */.json。以下代码展示了一个示例:spring-doc.cadn.net.cn

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWireMock(stubs="classpath:/stubs")
public class WiremockImportApplicationTests {

	@Autowired
	private Service service;

	@Test
	public void contextLoads() throws Exception {
		assertThat(this.service.go()).isEqualTo("Hello World!");
	}

}
实际上,WireMock 始终会从 src/test/resources/mappings 以及 stubs 属性中指定的自定义位置加载映射。若要更改此行为,您还可以指定一个文件根目录,具体说明请参见本文档的下一节
此外,stubs 位置中的映射不被视为 Wiremock 的“默认映射”组成部分,且在测试期间对 com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings 的调用不会导致 stubs 位置中的映射被包含在内。然而,org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener 会在每次测试类结束后重置映射(包括添加来自存根位置的映射),并可选地在每次测试方法结束后(由 wiremock.reset-mappings-after-each-test 属性控制)也进行重置。

如果您使用 Spring Cloud Contract 的默认存根 JAR 文件,您的存根将存储在 /META-INF/group-id/artifact-id/versions/mappings/ 文件夹中。如果您希望从该位置注册所有存根(包括所有嵌入式 JAR 文件中的存根),可以使用以下语法:spring-doc.cadn.net.cn

@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF...

使用文件指定存根实现

WireMock 可以从类路径或文件系统中的文件读取响应体。在文件系统的情况下,您可以在 JSON DSL 中看到响应具有 bodyFileName 而非(字面)body。这些文件是相对于一个根目录解析的(默认情况下为 src/test/resources/__files)。若要自定义此位置,您可以将 files 属性设置为 @AutoConfigureWireMock 注解中父目录的位置(换句话说,__files 是子目录)。您可以使用 Spring 资源语法来引用 file:…​classpath:…​ 的位置。不支持通用 URL。可以提供多个值的列表——在这种情况下,当 WireMock 需要查找响应体时,它会解析第一个存在的文件。spring-doc.cadn.net.cn

当你配置 files 根目录时,它也会对存根的自动加载产生影响,因为这些存根位于根目录下的一个名为 mappings 的子目录中。
files 对从 stubs 属性显式加载的存根没有影响。

替代方案:使用 JUnit 规则

为了获得更传统的 WireMock 使用体验,您可以使用 JUnit @Rules 来启动和停止服务器。为此,请使用 WireMockSpring 这个便捷类来获取一个 Options 实例,如下 示例 所示:spring-doc.cadn.net.cn

The @ClassRule means that the server shuts down after all the methods in this class have been run.spring-doc.cadn.net.cn

Rest Template 的宽松 SSL 验证

WireMock 允许您使用 https URL 协议来模拟一个“安全”的服务器。如果您的应用程序希望在集成测试中与该模拟服务器通信,会发现 SSL 证书无效(这通常是自安装证书的常见问题)。最佳选择通常是重新配置客户端以使用 http。如果此方法不可行,您可以要求 Spring 配置一个忽略 SSL 验证错误的 HTTP 客户端(仅在测试环境中如此操作)。spring-doc.cadn.net.cn

为了以最少的麻烦实现此功能,您需要在应用程序中使用 Spring Boot RestTemplateBuilder,如下例所示:spring-doc.cadn.net.cn

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
	return builder.build();
}

您需要 RestTemplateBuilder,因为构建器会通过回调传递以初始化它,从而可以在该点设置 SSL 验证。如果您在测试中使用 @AutoConfigureWireMock 注解或存根运行器,此操作会自动发生。如果您采用 JUnit @Rule 方法,则还需添加 @AutoConfigureHttpClient 注解,如下例所示:spring-doc.cadn.net.cn

@RunWith(SpringRunner.class)
@SpringBootTest("app.baseUrl=https://localhost:6443")
@AutoConfigureHttpClient
public class WiremockHttpsServerApplicationTests {

	@ClassRule
	public static WireMockClassRule wiremock = new WireMockClassRule(
			WireMockSpring.options().httpsPort(6443));
...
}

如果您使用 spring-boot-starter-test,则类路径中包含 Apache HTTP 客户端,它会被 RestTemplateBuilder 选中,并配置为忽略 SSL 错误。如果您使用默认的 java.net 客户端,则无需使用注解(但使用它也不会造成损害)。目前尚不支持其他客户端,但未来版本中可能会增加此功能。spring-doc.cadn.net.cn

要禁用自定义 RestTemplateBuilder,请将 wiremock.rest-template-ssl-enabled 属性设置为 falsespring-doc.cadn.net.cn

WireMock 和 Spring MVC 模拟

Spring Cloud Contract 提供了一个便捷的类,可将 JSON WireMock 模拟数据加载到 Spring MockRestServiceServer 中。以下 项目 展示了这一点。spring-doc.cadn.net.cn

baseUrl 会被添加到所有模拟调用的前面,而 stubs() 方法则接受一个存根路径资源模式作为参数。在前面的例子中,定义在 /stubs/resource.json 处的存根将被加载到模拟服务器中。如果 RestTemplate 被要求访问 example.org/,它将返回在该 URL 处所声明的响应。可以指定多个存根模式,每个模式可以是一个目录(用于递归列出所有 .json),一个固定文件名(如前面例子所示),或一个 Ant 风格的模式。JSON 格式为标准的 WireMock 格式,您可以在 WireMock 官方网站 上了解更多信息。spring-doc.cadn.net.cn

目前,Spring Cloud Contract Verifier 支持 Tomcat、Jetty 和 Undertow 作为 Spring Boot 嵌入式服务器,而 WireMock 本身对特定版本的 Jetty(当前为 9.2)具有“原生”支持。若要使用原生 Jetty,您需要添加原生 WireMock 依赖项,并排除 Spring Boot 容器(如果存在的话)。spring-doc.cadn.net.cn