SpringCloud 三分钟游

2023-12-06 17:04 更新

此简短的导览使用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-RSEXPLICIT。)

从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属性设置为JUNIT5Spock来使用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-idartifact-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}]


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号