5.5. 存根流道弹簧云
Stub Runner可以与Spring Cloud集成。
有关实际生活示例,请参阅:
5.5.1. 存根服务发现
最重要的特点是它存根:Stub Runner Spring Cloud
-
DiscoveryClient
-
ReactorServiceInstanceLoadBalancer
这意味着,无论您使用动物园管理员,领事,尤里卡还是任何东西。 否则,您在测试中不需要它。我们正在启动您的 WireMock 实例 依赖项,我们告诉您的应用程序,无论何时使用,都要加载 平衡直接调用那些存根服务器 而不是调用真正的服务发现工具。Feign
RestTemplate
DiscoveryClient
例如,以下测试通过:
def 'should make service discovery work'() {
expect: 'WireMocks are running'
"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
and: 'Stubs can be reached via load service discovery'
restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance'
restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer'
}
请注意,前面的示例需要以下配置文件:
stubrunner:
idsToServiceIds:
ivyNotation: someValueInsideYourCode
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
测试配置文件和服务发现
在集成测试中,您通常不希望调用发现服务(如 Eureka) 或配置服务器。这就是您创建要在其中禁用的其他测试配置的原因 这些功能。
由于春云公地的某些限制, 为此,您必须禁用这些属性 在静态块中,例如以下示例(对于 Eureka):
//Hack to work around https://github.com/spring-cloud/spring-cloud-commons/issues/156
static {
System.setProperty("eureka.client.enabled", "false");
System.setProperty("spring.cloud.config.failFast", "false");
}
5.5.2. 附加配置
您可以使用 themap 将存根与应用程序的名称进行匹配。artifactId
stubrunner.idsToServiceIds:
默认情况下,所有服务发现都是存根。这意味着,无论您是否有 一个现有的,其结果将被忽略。但是,如果你想重用它,你可以设置,然后你现有的结果是 与存根的合并。DiscoveryClient stubrunner.cloud.delegate.enabled true DiscoveryClient |
存根运行器使用的默认 Maven 配置可以调整 通过设置以下系统属性或设置相应的环境变量:
-
maven.repo.local
:自定义 maven 本地存储库位置的路径
-
org.apache.maven.user-settings
:自定义 maven 用户设置位置的路径
-
org.apache.maven.global-settings
:指向 maven 全局设置位置的路径
5.6. 使用存根运行器引导应用程序
Spring Cloud 合约存根运行程序启动是一个 Spring 启动应用程序,它将 REST 端点公开给 触发消息标签并访问 WireMock 服务器。
5.6.1. 存根运行程序引导安全性
存根运行程序启动应用程序在设计上不受保护 - 保护它需要为所有应用程序添加安全性 存根,即使它们实际上并不需要它。由于这是一个测试实用程序 - 服务器不适合在生产环境中使用。
预计只有受信任的客户端才能访问存根运行程序引导服务器。你不应该 在不受信任的位置将此应用程序作为胖罐或Docker 映像运行。 |
5.6.2. 存根运行服务器
要使用存根运行器服务器,请添加以下依赖项:
compile "org.springframework.cloud:spring-cloud-starter-stub-runner"
然后用注释一个类,构建一个胖罐子,它就可以工作了。@EnableStubRunnerServer
有关属性,请参阅存根流道弹簧部分。
5.6.3. 存根运行器服务器胖罐
您可以从 Maven 下载独立的 JAR(例如,对于版本 2.0.1.RELEASE) 通过运行以下命令:
$ wget -O stub-runner.jar 'https://search.maven.org/remotecontent?filepath=org/springframework/cloud/spring-cloud-contract-stub-runner-boot/2.0.1.RELEASE/spring-cloud-contract-stub-runner-boot-2.0.1.RELEASE.jar'
$ java -jar stub-runner.jar --stubrunner.ids=... --stubrunner.repositoryRoot=...
5.6.4. 春云命令行界面
从Spring Cloud CLI项目的版本开始,您可以通过运行来启动存根运行器引导。1.4.0.RELEASE
spring cloud stubrunner
要传递配置,您可以在当前工作目录中创建一个文件, 在调用的子目录中,或 in。该文件可能类似于以下内容 运行本地安装的存根的示例:stubrunner.yml
config
~/.spring-cloud
例 2.stubrunner.yml
stubrunner:
stubsMode: LOCAL
ids:
- com.example:beer-api-producer:+:9876
然后,您可以从终端窗口调用以启动 存根运行器服务器。它在港口可用。spring cloud stubrunner
8750
5.6.5. 端点
存根运行程序启动提供两个终结点:
HTTP
对于 HTTP,存根运行程序启动使以下终结点可用:
- GET:返回所有正在运行的存根注释的列表
/stubs
ivy:integer
- GET:返回给定表示法的端口(调用端点时也可以是)
/stubs/{ivy}
ivy
ivy
artifactId
消息
对于消息传递,存根运行程序引导使以下端点可用:
- GET:返回所有正在运行的标签注释的列表
/triggers
ivy : [ label1, label2 …]
- 开机自检:运行触发器
/triggers/{label}
label
- POST:运行带有给定符号的触发器 (调用端点时,也可以只)
/triggers/{ivy}/{label}
label
ivy
ivy
artifactId
5.6.6. 例子
以下示例显示了存根运行程序引导的典型用法:
@SpringBootTest(classes = StubRunnerBoot, properties = "spring.cloud.zookeeper.enabled=false")
@ActiveProfiles("test")
class StubRunnerBootSpec extends Specification {
@Autowired
StubRunning stubRunning
def setup() {
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning),
new TriggerController(stubRunning))
}
def 'should return a list of running stub servers in "full ivy:port" notation'() {
when:
String response = RestAssuredMockMvc.get('/stubs').body.asString()
then:
def root = new JsonSlurper().parseText(response)
root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs' instanceof Integer
}
def 'should return a port on which a [#stubId] stub is running'() {
when:
def response = RestAssuredMockMvc.get("/stubs/${stubId}")
then:
response.statusCode == 200
Integer.valueOf(response.body.asString()) > 0
where:
stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
'org.springframework.cloud.contract.verifier.stubs:bootService:+',
'org.springframework.cloud.contract.verifier.stubs:bootService',
'bootService']
}
def 'should return 404 when missing stub was called'() {
when:
def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
then:
response.statusCode == 404
}
def 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
when:
String response = RestAssuredMockMvc.get('/triggers').body.asString()
then:
def root = new JsonSlurper().parseText(response)
root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["delete_book", "return_book_1", "return_book_2"])
}
def 'should trigger a messaging label'() {
given:
StubRunning stubRunning = Mock()
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
when:
def response = RestAssuredMockMvc.post("/triggers/delete_book")
then:
response.statusCode == 200
and:
1 * stubRunning.trigger('delete_book')
}
def 'should trigger a messaging label for a stub with [#stubId] ivy notation'() {
given:
StubRunning stubRunning = Mock()
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
when:
def response = RestAssuredMockMvc.post("/triggers/$stubId/delete_book")
then:
response.statusCode == 200
and:
1 * stubRunning.trigger(stubId, 'delete_book')
where:
stubId << ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
}
def 'should throw exception when trigger is missing'() {
when:
RestAssuredMockMvc.post("/triggers/missing_label")
then:
Exception e = thrown(Exception)
e.message.contains("Exception occurred while trying to return [missing_label] label.")
e.message.contains("Available labels are")
e.message.contains("org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs=[]")
e.message.contains("org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs=")
}
}
5.6.7. 使用服务发现的存根运行程序引导
使用存根运行器引导的一种方法是将其用作“冒烟测试”的存根馈送。那是什么意思? 假设您不想按顺序将 50 个微服务部署到测试环境 以查看您的应用程序是否正常工作。您已经在构建过程中运行了一套测试, 但您还希望确保应用程序的打包正常工作。您可以 将应用程序部署到环境中,启动它,然后对其运行几个测试以查看是否 它有效。我们可以称这些测试为“烟雾测试”,因为它们的目的是只检查少数几个 的测试场景。
这种方法的问题在于,如果你使用微服务,你很可能也 使用服务发现工具。存根运行程序引导允许您通过启动 所需的存根,并在服务发现工具中注册它们。考虑以下示例 尤里卡的这种设置(假设尤里卡已经在运行):
@SpringBootApplication
@EnableStubRunnerServer
@EnableEurekaClient
@AutoConfigureStubRunner
public class StubRunnerBootEurekaExample {
public static void main(String[] args) {
SpringApplication.run(StubRunnerBootEurekaExample.class, args);
}
}
我们要启动存根运行器引导服务器(),启用尤里卡客户端(), 并打开存根运行程序功能()。@EnableStubRunnerServer
@EnableEurekaClient
@AutoConfigureStubRunner
现在假设我们要启动此应用程序,以便自动注册存根。 我们可以通过运行应用程序来做到这一点,其中包含以下属性列表:java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar
${SYSTEM_PROPS}
* -Dstubrunner.repositoryRoot=https://repo.spring.io/snapshot (1)
* -Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
* -Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.
* springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.
* cloud.contract.verifier.stubs:bootService (3)
* -Dstubrunner.idsToServiceIds.fraudDetectionServer=
* someNameThatShouldMapFraudDetectionServer (4)
*
* (1) - we tell Stub Runner where all the stubs reside (2) - we don't want the default
* behaviour where the discovery service is stubbed. That's why the stub registration will
* be picked (3) - we provide a list of stubs to download (4) - we provide a list of
这样,您部署的应用程序可以通过服务向启动的 WireMock 服务器发送请求 发现。最有可能的是,点 1 到 3 可以默认设置,因为它们不是 可能会改变。这样,您只需提供启动时要下载的存根列表 存根运行器引导。application.yml
5.7. 消费者驱动的合同:每个消费者的存根
在某些情况下,同一终结点的两个使用者希望有两个不同的响应。
此方法还可以让您立即知道哪个使用者使用 API 的哪个部分。 您可以删除 API 生成的部分响应,并查看哪些自动生成的测试 失败。如果没有失败,您可以安全地删除响应的该部分,因为没有人使用它。 |
考虑以下为称为 它有两个使用者(和):producer
foo-consumer
bar-consumer
消费者foo-service
request {
url '/foo'
method GET()
}
response {
status OK()
body(
foo: "foo"
}
}
消费者bar-service
request {
url '/bar'
method GET()
}
response {
status OK()
body(
bar: "bar"
}
}
不能为同一请求生成两个不同的响应。这就是为什么您可以正确打包 合同,然后从该功能中获利。stubsPerConsumer
在生产者端,使用者可以拥有一个包含仅与他们相关的合同的文件夹。 通过将 theflag 设置为 ,我们不再注册所有存根,而只注册那些 对应于使用者应用程序的名称。换句话说,我们扫描每个存根的路径,并且, 如果它包含路径中具有使用者名称的子文件夹,则只有这样才会注册。stubrunner.stubs-per-consumer
true
在生产者方面,合同看起来像这样foo
.
└── contracts
├── bar-consumer
│ ├── bookReturnedForBar.groovy
│ └── shouldCallBar.groovy
└── foo-consumer
├── bookReturnedForFoo.groovy
└── shouldCallFoo.groovy
消费者可以设置理论或 theto,或者,您可以按如下方式设置测试:bar-consumer
spring.application.name
stubrunner.consumer-name
bar-consumer
@SpringBootTest(classes = Config, properties = ["spring.application.name=bar-consumer"])
@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
repositoryRoot = "classpath:m2repo/repository/",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@ActiveProfiles("streamconsumer")
class StubRunnerStubsPerConsumerSpec extends Specification {
...
}
然后,仅允许引用在其名称中包含路径(即文件夹中的路径)下注册的存根。bar-consumer
src/test/resources/contracts/bar-consumer/some/contracts/…
您还可以显式设置使用者名称,如下所示:
@SpringBootTest(classes = Config)
@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
repositoryRoot = "classpath:m2repo/repository/",
consumerName = "foo-consumer",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@ActiveProfiles("streamconsumer")
class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {
...
}
然后,只允许引用在包含其名称的路径下注册的存根(即文件夹中的存根)。foo-consumer
src/test/resources/contracts/foo-consumer/some/contracts/…
5.8. 从一个位置获取存根或合约定义
而不是从中选取存根或协定定义 Artifactory,Nexus或Git,你可以指向 驱动器或类路径上的位置。这样做在多模块项目中特别有用,其中一个模块需要 重用另一个模块的存根或协定,而无需 需要在本地 Maven 中实际安装它们 存储库以将这些更改提交到 Git。
为了实现这一点,您可以在设置存储库根参数时使用协议 在存根运行器或 Spring Cloud 合约插件中。stubs://
在此示例中,项目已成功 在文件夹下生成了构建和存根。作为使用者,可以使用协议设置存根运行程序以从该位置选取存根。producer
target/stubs
stubs://
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "stubs://file://location/to/the/producer/target/stubs/",
ids = "com.example:some-producer")
合同和存根可以存储在一个位置,每个生产者都有自己的专用文件夹,用于合同和存根映射。在该文件夹下,每个使用者都可以有自己的设置。若要使存根运行程序从提供的 ID 中找到专用文件夹,可以传递属性或系统属性。 以下清单显示了合同和存根的排列:stubs.find-producer=true
stubrunner.stubs.find-producer=true
└── com.example
├── some-artifact-id
│ └── 0.0.1
│ ├── contracts
│ │ └── shouldReturnStuffForArtifactId.groovy
│ └── mappings
│ └── shouldReturnStuffForArtifactId.json
└── some-other-artifact-id
├── contracts
│ └── shouldReturnStuffForOtherArtifactId.groovy
└── mappings
└── shouldReturnStuffForOtherArtifactId.json
使用者的组 ID |
具有工件 ID 的使用者 [某些工件 ID] |
具有工件 ID [某些工件 ID] 的使用者的合约 |
具有项目 ID 的使用者的映射 [some-artifact-id] |
具有工件 ID 的使用者 [其他工件 ID] |
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "stubs://file://location/to/the/contracts/directory",
ids = "com.example:some-producer",
properties="stubs.find-producer=true")
5.9. 在运行时生成存根
作为使用者,您可能不希望等待生成者完成其实现,然后发布其存根。此问题的解决方案可以在运行时生成存根。
作为生产者,定义合约时,您需要使生成的测试通过,以便发布存根。在某些情况下,您希望取消阻止使用者,以便他们可以在您的测试实际通过之前获取存根。在这种情况下,应将此类合同设置为进行中。您可以在“正在进行的合同”部分下阅读有关此内容的更多信息。这样,不会生成测试,但会生成存根。
作为使用者,您可以切换开关以在运行时生成存根。存根运行程序忽略所有现有的存根映射,并为所有协定定义生成新的映射。另一种选择是传递系统属性。以下示例显示了此类设置:stubrunner.generate-stubs
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "stubs://file://location/to/the/contracts",
ids = "com.example:some-producer",
generateStubs = true)
5.10. 无存根失败
默认情况下,如果未找到存根,存根运行程序将失败。若要更改该行为,请在注释中设置属性或在 JUnit 规则或扩展上调用该方法。以下示例演示如何执行此操作:failOnNoStubs
false
withFailOnNoStubs(false)
@AutoConfigureStubRunner(
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "stubs://file://location/to/the/contracts",
ids = "com.example:some-producer",
failOnNoStubs = false)
5.11. 通用属性
本节简要介绍常见属性,包括:
- JUnit 和 Spring 的通用属性
- 存根运行程序存根 ID
5.11.1. JUnit 和 Spring 的通用属性
您可以使用系统属性或 Spring 配置来设置重复属性 性能。下表显示了其名称及其默认值:
属性名称 |
默认值 |
描述 |
stubrunner.minPort |
10000 |
带有存根的已启动 WireMock 的端口的最小值。 |
stubrunner.maxPort |
15000 |
带有存根的已启动 WireMock 的端口的最大值。 |
stubrunner.repositoryRoot |
|
Maven repository URL.如果为空,则调用本地 Maven 存储库。 |
stubrunner.classifier |
stubs |
存根项目的默认分类器。 |
stubrunner.stubsMode |
CLASSPATH |
要获取和注册存根的方式。 |
stubrunner.ids |
|
要下载的常春藤符号存根数组。 |
stubrunner.username |
|
可选用户名,用于访问存储 JAR 的工具 存根。 |
stubrunner.password |
|
可选密码,用于访问存储 JAR 的工具 存根。 |
stubrunner.stubsPerConsumer |
false |
设置为 如果要将不同的存根用于 每个使用者,而不是为每个使用者注册所有存根。true |
stubrunner.consumerName |
|
如果要为每个使用者使用存根,并且想要 覆盖使用者名称,更改此值。 |
5.11.2. 存根运行器存根 ID
您可以在系统属性中设置要下载的存根。他们 使用以下模式:stubrunner.ids
groupId:artifactId:version:classifier:port
请注意,和是可选的。version
classifier
port
- 如果您不提供,则随机选择一个。
port
- 如果未提供,则使用默认值。(请注意,您可以 以这种方式传递一个空分类器:)。
classifier
groupId:artifactId:version:
- 如果您不提供,则通过,最新的是 下载。
version
+
port
表示 WireMock 服务器的端口。
从版本 1.0.4 开始,您可以提供一系列版本 希望存根运行器考虑在内。您可以阅读有关 以太版本控制范围在这里。 |
6. 春云合约电汇模拟
Spring Cloud 合约 WireMock 模块允许您在 弹簧启动应用程序。有关更多详细信息,请查看示例。
如果你有一个使用 Tomcat 作为嵌入式服务器的 Spring Boot 应用程序(这是 默认为),您可以添加到类路径中,并在测试中使用 Wiremock。Wiremock 作为存根服务器运行,而您 可以通过使用 Java API 或使用静态 JSON 声明作为 您的测试。以下代码显示了一个示例:spring-boot-starter-web
spring-cloud-starter-contract-stub-runner
@AutoConfigureWireMock
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(port = 0)
public class WiremockForDocsTests {
// A service that calls out over HTTP
@Autowired
private Service service;
@BeforeEach
public void setup() {
this.service.setBase("http://localhost:"
+ this.environment.getProperty("wiremock.server.port"));
}
// Using the WireMock APIs in the normal way:
@Test
public void contextLoads() throws Exception {
// Stubbing WireMock
stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
// We're asserting if WireMock responded properly
assertThat(this.service.go()).isEqualTo("Hello World!");
}
}
要在其他端口上启动存根服务器,请使用(例如)。对于随机端口,请使用值 of。存根 服务器端口可以在测试应用程序上下文中与属性绑定。使用添加类型到 测试应用程序上下文,在方法和类之间缓存 具有相同的上下文。Spring 集成测试也是如此。另外,您可以 将类型的 bean 注入到您的测试中。 注册的 WireMock 服务器在每个测试类后重置。 但是,如果需要在每个测试方法之后重置它,请将属性设置为 。@AutoConfigureWireMock(port=9999)
0
wiremock.server.port
@AutoConfigureWireMock
WiremockConfiguration
WireMockServer
wiremock.reset-mappings-after-each-test
true
6.1. 自动注册存根
如果使用,它会从文件中注册 WireMock JSON 存根 系统或类路径(缺省情况下为 from)。您可以 通过使用注释中的属性自定义位置,该属性可以是 Ant 样式的资源模式或目录。在目录的情况下,是 附加。以下代码显示了一个示例:@AutoConfigureWireMock
file:src/test/resources/mappings
stubs
*/.json
@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总是从as加载映射。 以及属性中的自定义位置。若要更改此行为,可以 还要指定文件根目录,如本文档的下一节所述。src/test/resources/mappings stubs |
此外,位置中的映射不被视为Wiremock的“默认映射”和调用的一部分 在测试期间不会导致映射 在包含的位置。但是,在每个测试类之后重置映射(包括从存根位置添加映射),并且可以选择 在每种测试方法之后(由财产保护)。stubs com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings stubs org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener wiremock.reset-mappings-after-each-test |
如果您使用春云合约的默认存根罐,您的 存根存储在文件夹中。 如果要从该位置注册所有嵌入式 JAR 中的所有存根,可以使用 以下语法:/META-INF/group-id/artifact-id/versions/mappings/
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF/**/mappings/**/*.json")
6.2. 使用文件指定存根主体
WireMock 可以从类路径或文件系统上的文件中读取响应正文。在 在文件系统的情况下,您可以在 JSON DSL 中看到响应具有 a而不是 (字面意思)。这些文件是相对于根目录解析的(默认情况下)。要自定义此位置,可以将注释中的属性设置为父项的位置 目录(换句话说,是一个子目录)。您可以使用 Spring 资源 表示法以引用位置。通用网址不是 支持。可以给出一个值列表 — 在这种情况下,WireMock 解析第一个文件 当它需要找到响应正文时,它就存在。bodyFileName
body
src/test/resources/__files
files
@AutoConfigureWireMock
__files
file:…
classpath:…
配置根时,它还会影响 自动加载存根,因为它们来自根位置 在名为的子目录中。files mappings |
的值没有 对从属性显式加载的存根的影响。files stubs |
6.3. 替代方案:使用 JUnit 规则
对于更传统的 WireMock 体验,您可以使用 JUnitto 启动和停止 服务器。为此,请使用便利类获取实例,如以下示例所示:@Rules
WireMockSpring
Options
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class WiremockForDocsClassRuleTests {
// Start WireMock on some dynamic port
// for some reason `dynamicPort()` is not working properly
public static WireMockServer wiremock = new WireMockServer(WireMockSpring.options().dynamicPort());
@BeforeAll
static void setupClass() {
wiremock.start();
}
@AfterEach
void after() {
wiremock.resetAll();
}
@AfterAll
static void clean() {
wiremock.shutdown();
}
// A service that calls out over HTTP to wiremock's port
@Autowired
private Service service;
@BeforeEach
public void setup() {
this.service.setBase("http://localhost:" + wiremock.port());
}
// Using the WireMock APIs in the normal way:
@Test
public void contextLoads() throws Exception {
// Stubbing WireMock
wiremock.stubFor(get(urlEqualTo("/resource")).willReturn(aResponse()
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
// We're asserting if WireMock responded properly
assertThat(this.service.go()).isEqualTo("Hello World!");
}
}
这意味着服务器在此类中的所有方法之后关闭 已经运行。@ClassRule
6.4. 放宽 SSL 验证的 rest 模板
WireMock允许您使用URL协议存根“安全”服务器。如果你的 应用程序想要在集成测试中联系该存根服务器,它发现 SSL 证书无效(自安装证书的常见问题)。 最好的选择通常是重新配置要使用的客户端。如果这不是 选项,您可以要求 Spring 配置忽略 SSL 验证错误的 HTTP 客户端 (当然,这样做仅用于测试)。https
http
为了以最小的麻烦完成这项工作,您需要使用Spring Bootin您的应用程序,如以下示例所示:RestTemplateBuilder
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
你需要因为构建器是通过回调传递到 初始化它,以便此时可以在客户端中设置 SSL 验证。这 如果使用注释或存根运行器,则在测试中自动发生。如果使用 JUnit 方法,则还需要添加注释,如以下示例所示:RestTemplateBuilder
@AutoConfigureWireMock
@Rule
@AutoConfigureHttpClient
@RunWith(SpringRunner.class)
@SpringBootTest("app.baseUrl=https://localhost:6443")
@AutoConfigureHttpClient
public class WiremockHttpsServerApplicationTests {
@ClassRule
public static WireMockClassRule wiremock = new WireMockClassRule(
WireMockSpring.options().httpsPort(6443));
...
}
如果您使用,则在 类路径,并且它被选择并配置为忽略SSL 错误。如果使用默认客户端,则不需要注释(但它 没有伤害)。目前不支持其他客户端,但可以添加 在将来的版本中。spring-boot-starter-test
RestTemplateBuilder
java.net
若要禁用自定义,请将属性设置为。RestTemplateBuilder
wiremock.rest-template-ssl-enabled
false
6.5. WireMock 和 Spring MVC Mocks
Spring Cloud Contract 提供了一个方便的类,可以将 JSON WireMock 存根加载到 一个春天。以下代码显示了一个示例:MockRestServiceServer
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class WiremockForDocsMockServerApplicationTests {
@Autowired
private RestTemplate restTemplate;
@Autowired
private Service service;
@Test
public void contextLoads() throws Exception {
// will read stubs classpath
MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
.baseUrl("https://example.org").stubs("classpath:/stubs/resource.json")
.build();
// We're asserting if WireMock responded properly
assertThat(this.service.go()).isEqualTo("Hello World");
server.verify();
}
}
该值附加到所有模拟调用的前面,该方法采用存根 路径资源模式作为参数。在前面的示例中,定义的存根 atis 加载到模拟服务器中。如果被要求 访问,它会将响应作为在该 URL 上声明。更多 可以指定一个以上的存根模式,每个模式都可以是一个目录(对于递归 全部列表)、固定文件名(如前面的示例所示)或 Ant 样式 模式。JSON格式是普通的WireMock格式,您可以在WireMock网站上阅读。baseUrl
stubs()
/stubs/resource.json
RestTemplate
example.org/
.json
目前,Spring Cloud 合约验证器支持 Tomcat、Jetty 和 Undertow 作为 Spring Boot嵌入式服务器,Wiremock本身对特定的“本机”支持。 Jetty 的版本(当前为 9.2)。要使用本机码头,您需要添加本机 连接依赖关系并排除 Spring Boot 容器(如果有的话)。