SpringCloud 三分钟游
此简短的导览使用Spring Cloud Contract来完成:
- 名为“在生产者端”的部分
- “消费者方面”一节
您可以在这里找到更简短的导览 。
要开始使用Spring Cloud Contract
,请将具有REST/
消息传递合同(以Groovy DSL或YAML表示)的文件添加到由contractsDslDir
属性设置的合同目录中。默认情况下,它是$rootDir/src/test/resources/contracts
。
对于HTTP存根,合同定义了应针对给定请求返回的响应类型(考虑到HTTP方法,URL,标头,状态码等)。以下示例显示了Groovy DSL中的HTTP存根如何收缩:
package contracts org.springframework.cloud.contract.spec.Contract.make { request { method 'PUT' url '/fraudcheck' body([ "client.id": $(regex('[0-9]{10}')), loanAmount: 99999 ]) headers { contentType('application/json') } } response { status OK() body([ fraudCheckStatus: "FRAUD", "rejection.reason": "Amount too high" ]) headers { contentType('application/json') } } }
YAML中表示的同一合同应类似于以下示例:
request: method: PUT url: /fraudcheck body: "client.id": 1234567890 loanAmount: 99999 headers: Content-Type: application/json matchers: body: - path: $.['client.id'] type: by_regex value: "[0-9]{10}" response: status: 200 body: fraudCheckStatus: "FRAUD" "rejection.reason": "Amount too high" headers: Content-Type: application/json;charset=UTF-8
对于消息传递,可以定义:
- 可以定义输入和输出消息(考虑发送消息的位置和位置,消息正文和标头)。
- 收到消息后应调用的方法。
- 调用时应触发消息的方法。
以下示例显示了以Groovy DSL表示的骆驼消息传递协定:
def contractDsl = Contract.make { label 'some_label' input { messageFrom('jms:delete') messageBody([ bookName: 'foo' ]) messageHeaders { header('sample', 'header') } assertThat('bookWasDeleted()') } }
以下示例显示了用YAML表示的同一合同:
label: some_label input: messageFrom: jms:delete messageBody: bookName: 'foo' messageHeaders: sample: header assertThat: bookWasDeleted()
然后,您可以将Spring Cloud Contract Verifier依赖项和插件添加到您的构建文件中,如以下示例所示:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-verifier</artifactId> <scope>test</scope> </dependency>
以下清单显示了如何添加插件,该插件应放在文件的build / plugins部分中:
<plugin> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-contract-maven-plugin</artifactId> <version>${spring-cloud-contract.version}</version> <extensions>true</extensions> </plugin>
运行./mvnw clean install
会自动生成测试,以验证应用程序是否符合添加的合同。默认情况下,生成的测试在org.springframework.cloud.contract.verifier.tests.
下。
以下示例显示了自动生成的HTTP合同测试示例:
@Test public void validate_shouldMarkClientAsFraud() throws Exception { // given: MockMvcRequestSpecification request = given() .header("Content-Type", "application/vnd.fraud.v1+json") .body("{\"client.id\":\"1234567890\",\"loanAmount\":99999}"); // when: ResponseOptions response = given().spec(request) .put("/fraudcheck"); // then: assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); assertThatJson(parsedJson).field("['fraudCheckStatus']").matches("[A-Z]{5}"); assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high"); }
前面的示例使用Spring的MockMvc
运行测试。这是HTTP合同的默认测试模式。但是,也可以使用JAX-RS客户端和显式HTTP调用。(为此,请将插件的testMode
属性分别更改为JAX-RS
或EXPLICIT
。)
从2.1.0版开始,也可以使用RestAssuredWebTestClient`with Spring’s reactive `WebTestClient
在后台运行。在使用基于Web-Flux
的响应式应用程序时,特别推荐使用此方法。为了使用WebTestClient
,请将testMode
设置为WEBTESTCLIENT
。
这是在WEBTESTCLIENT
测试模式下生成的测试的示例:
[source,java,indent=0]
@Test public void validate_shouldRejectABeerIfTooYoung() throws Exception { // given: WebTestClientRequestSpecification request = given() .header("Content-Type", "application/json") .body("{\"age\":10}"); // when: WebTestClientResponse response = given().spec(request) .post("/check"); // then: assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).matches("application/json.*"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); assertThatJson(parsedJson).field("['status']").isEqualTo("NOT_OK"); }
除了默认的JUnit 4,您可以通过将插件的testFramework
属性设置为JUNIT5
或Spock
来使用JUnit 5或Spock测试。
现在,您还可以基于合同生成WireMock方案,方法是在合同文件名的开头添加订单号,后跟下划线。
以下示例显示了在Spock中为消息存根合约自动生成的测试:
[source,groovy,indent=0]
given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( \'\'\'{"bookName":"foo"}\'\'\', ['sample': 'header'] ) when: contractVerifierMessaging.send(inputMessage, 'jms:delete') then: noExceptionThrown() bookWasDeleted()
由于尚不存在合同描述的功能的实现,因此测试失败。
要使它们通过,您必须添加处理HTTP请求或消息的正确实现。另外,您必须为自动生成的测试添加正确的基础测试类。该类由所有自动生成的测试扩展,并且应包含运行它们所需的所有设置(例如,RestAssuredMockMvc
控制器设置或消息传递测试设置)。
一旦实现和测试基类就位,测试就会通过,并且将应用程序和存根构件都构建并安装在本地Maven存储库中。有关将存根jar安装到本地存储库的信息显示在日志中,如以下示例所示:
[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server --- [INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar [INFO] [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server --- [INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar [INFO] [INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server --- [INFO] [INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server --- [INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar [INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom [INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
现在,您可以合并更改,并在在线存储库中发布应用程序和存根工件。
Docker项目
为了在使用非JVM技术创建应用程序时启用合同,已经创建了springcloud/spring-cloud-contract
Docker映像。它包含一个项目,该项目会自动为HTTP合同生成测试并以EXPLICIT
测试模式执行它们。然后,如果测试通过,它将生成Wiremock存根并将其发布到工件管理器(可选)。
为了使用该映像,您可以将合同挂载到/contracts
目录中并设置一些环境变量。
Spring Cloud Contract Stub Runner
可用于集成测试中,以获取模拟实际服务的正在运行的WireMock实例或消息传递路由。
首先,将依赖项添加到Spring Cloud Contract Stub Runner
:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> </dependency>
您可以通过以下两种方式之一在Maven存储库中安装生产者端存根:
-
通过检出生产者端存储库并添加合同并通过运行以下命令来生成存根:
$ cd local-http-server-repo $ ./mvnw clean install -DskipTests
由于生产者方合同实施尚未到位,因此跳过了测试,因此自动生成的合同测试失败。
-
从远程存储库获取已经存在的生产者服务存根。为此,请将存根工件标识和工件存储库UR1作为
Spring Cloud Contract Stub Runner
属性传递,如以下示例所示:stubrunner: ids: 'com.example:http-server-dsl:+:stubs:8080' repositoryRoot: https://repo.spring.io/libs-snapshot
现在,您可以使用@AutoConfigureStubRunner
注释测试类。在注释中,为Spring Cloud Contract Stub Runner
提供group-id
和artifact-id
以便为您运行协作者的存根,如以下示例所示:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=WebEnvironment.NONE) @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public class LoanApplicationServiceTests {
从在线存储库下载存根时,请使用
REMOTE
stubsMode
,而对于脱机工作,请使用LOCAL
。
在集成测试中,您可以接收HTTP响应的残存版本或预期由协作服务发出的消息。您可以在构建日志中看到类似于以下内容的条目:
2016-07-19 14:22:25.403 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Desired version is + - will try to resolve the latest version 2016-07-19 14:22:25.438 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is 0.0.1-SNAPSHOT 2016-07-19 14:22:25.439 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories [] 2016-07-19 14:22:25.451 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar 2016-07-19 14:22:25.465 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar] 2016-07-19 14:22:25.475 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265] 2016-07-19 14:22:27.737 INFO 41050 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]
更多建议: