Spring Cloud 合约功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud 合约功能相关的知识,希望对你有一定的参考价值。

Spring

4.4. 消费者存根生成

与 HTTP 部分不同,在消息传递中,我们需要在 JAR 中发布合约定义 一个存根。然后在消费者端解析它,并创建适当的存根路由。

如果类路径上有多个框架,则存根运行程序需要 定义应使用哪一个。假设你有AMQP、Spring Cloud Stream和Spring Integration。 在类路径上,并且您想要使用 Spring AMQP。然后你需要设置。 这样,唯一剩下的框架就是Spring AMQP。​​stubrunner.stream.enabled=false​​​​stubrunner.integration.enabled=false​

4.4.1. 存根触发

要触发消息,请使用接口,如以下示例所示:​​StubTrigger​

package org.springframework.cloud.contract.stubrunner;

import java.util.Collection;
import java.util.Map;

/**
* Contract for triggering stub messages.
*
* @author Marcin Grzejszczak
*/
public interface StubTrigger

/**
* Triggers an event by a given label for a given @code groupid:artifactid notation.
* You can use only @code artifactId too.
*
* Feature related to messaging.
* @param ivyNotation ivy notation of a stub
* @param labelName name of the label to trigger
* @return true - if managed to run a trigger
*/
boolean trigger(String ivyNotation, String labelName);

/**
* Triggers an event by a given label.
*
* Feature related to messaging.
* @param labelName name of the label to trigger
* @return true - if managed to run a trigger
*/
boolean trigger(String labelName);

/**
* Triggers all possible events.
*
* Feature related to messaging.
* @return true - if managed to run a trigger
*/
boolean trigger();

/**
* Feature related to messaging.
* @return a mapping of ivy notation of a dependency to all the labels it has.
*/
Map<String, Collection<String>> labels();

为方便起见,界面扩展,因此您只需要一个 或测试中的其他。​​StubFinder​​​​StubTrigger​

​StubTrigger​​提供以下选项来触发消息:

  • 按标签触发
  • 按组和项目 ID 触发
  • 由项目 ID 触发
  • 触发所有消息

4.4.2. 标签触发

以下示例演示如何触发带有标签的消息:

stubFinder.trigger(return_book_1)

4.4.3. 按组和工件 ID 触发

以下示例演示如何按组和项目 ID 触发消息:

stubFinder.trigger(org.springframework.cloud.contract.verifier.stubs:streamService, return_book_1)

4.4.4. 由工件 ID 触发

以下示例演示如何从项目 ID 触发消息:

stubFinder.trigger(streamService, return_book_1)

4.4.5. 触发所有消息

以下示例演示如何触发所有消息:

stubFinder.trigger()

4.5. 使用 Apache Camel 的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块为您提供了一种与 Apache Camel 集成的简单方法。 对于提供的工件,它会自动下载存根并注册所需的 路线。

4.5.1. 将 Apache Camel 添加到项目中

您可以在类路径上同时拥有 Apache Camel 和 Spring Cloud 合约存根运行程序。 记得用注释你的测试类。​​@AutoConfigureStubRunner​

4.5.2. 禁用该功能

如果需要禁用此功能,请设置该属性。​​stubrunner.camel.enabled=false​

4.5.3. 例子

假设我们有以下 Maven 存储库,其中包含为应用程序部署的存根:​​camelService​

└── .m2
└── repository
└── io
└── codearte
└── accurest
└── stubs
└── camelService
├── 0.0.1-SNAPSHOT
│ ├── camelService-0.0.1-SNAPSHOT.pom
│ ├── camelService-0.0.1-SNAPSHOT-stubs.jar
│ └── maven-metadata-local.xml
└── maven-metadata-local.xml

进一步假设存根包含以下结构:

├── META-INF
│ └── MANIFEST.MF
└── repository
├── accurest
│ ├── bookDeleted.groovy
│ ├── bookReturned1.groovy
│ └── bookReturned2.groovy
└── mappings

现在考虑以下合同(我们将其编号为 1 和 2):

Contract.make 
label return_book_1
input
triggeredBy(bookReturnedTriggered())

outputMessage
sentTo(jms:output)
body( "bookName" : "foo" )
headers
header(BOOK-NAME, foo)


Contract.make 
label return_book_2
input
messageFrom(jms:input)
messageBody([
bookName: foo
])
messageHeaders
header(sample, header)


outputMessage
sentTo(jms:output)
body([
bookName: foo
])
headers
header(BOOK-NAME, foo)


这些示例适用于三种方案:

  1. 方案 1(无输入消息)
  2. 场景 2(由输入触发的输出)
  3. 场景 3(无输出的输入)
方案 1(无输入消息)

要触发来自标签的消息,我们使用接口,如下所示:​​return_book_1​​​​StubTrigger​

stubFinder.trigger(return_book_1)

接下来,我们要侦听发送到以下消息的输出:​​jms:output​

Exchange receivedMessage = consumerTemplate.receive(jms:output, 5000)

然后,收到的消息将传递以下断言:

receivedMessage != null
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
receivedMessage.in.headers.get(BOOK-NAME) == foo
场景 2(由输入触发的输出)

由于路由已为您设置,因此您可以向目的地发送消息。​​jms:output​

producerTemplate.
sendBodyAndHeaders(jms:input, new BookReturned(foo), [sample: header])

接下来,我们要监听发送到的消息的输出,如下所示:​​jms:output​

Exchange receivedMessage = consumerTemplate.receive(jms:output, 5000)

收到的消息将传递以下断言:

receivedMessage != null
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
receivedMessage.in.headers.get(BOOK-NAME) == foo
场景 3(无输出的输入)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​jms:output​

producerTemplate.
sendBodyAndHeaders(jms:delete, new BookReturned(foo), [sample: header])

4.6. 带有 Spring 集成的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块为您提供了一种简单的方法 与弹簧集成集成。对于提供的工件,它会自动下载 存根并注册所需的路由。

4.6.1. 将运行器添加到项目中

您可以在 类路径。记得用注释你的测试类。​​@AutoConfigureStubRunner​

4.6.2. 禁用该功能

如果需要禁用此功能,请设置该属性。​​stubrunner.integration.enabled=false​

4.6.3. 例子

假设您有以下 Maven 存储库,其中包含为应用程序部署的存根:​​integrationService​

└── .m2
└── repository
└── io
└── codearte
└── accurest
└── stubs
└── integrationService
├── 0.0.1-SNAPSHOT
│ ├── integrationService-0.0.1-SNAPSHOT.pom
│ ├── integrationService-0.0.1-SNAPSHOT-stubs.jar
│ └── maven-metadata-local.xml
└── maven-metadata-local.xml

进一步假设存根包含以下结构:

├── META-INF
│ └── MANIFEST.MF
└── repository
├── accurest
│ ├── bookDeleted.groovy
│ ├── bookReturned1.groovy
│ └── bookReturned2.groovy
└── mappings

考虑以下合同(编号为 1 和 2):

Contract.make 
label return_book_1
input
triggeredBy(bookReturnedTriggered())

outputMessage
sentTo(output)
body( "bookName" : "foo" )
headers
header(BOOK-NAME, foo)


Contract.make 
label return_book_2
input
messageFrom(input)
messageBody([
bookName: foo
])
messageHeaders
header(sample, header)


outputMessage
sentTo(output)
body([
bookName: foo
])
headers
header(BOOK-NAME, foo)


现在考虑以下 Spring 集成路线:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">


<!-- REQUIRED FOR TESTING -->
<bridge input-channel="output"
output-channel="outputTest"/>

<channel id="outputTest">
<queue/>
</channel>

</beans:beans>

这些示例适用于三种方案:

  1. 方案 1(无输入消息)
  2. 场景 2(由输入触发的输出)
  3. 场景 3(无输出的输入)
方案 1(无输入消息)

要从标签触发消息,请使用接口,作为 遵循:​​return_book_1​​​​StubTrigger​

stubFinder.trigger(return_book_1)

下面的清单显示了如何侦听发送到的消息的输出:​​jms:output​

Message<?> receivedMessage = messaging.receive(outputTest)

收到的消息将传递以下断言:

receivedMessage != null
assertJsons(receivedMessage.payload)
receivedMessage.headers.get(BOOK-NAME) == foo
场景 2(由输入触发的输出)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​jms:output​

messaging.send(new BookReturned(foo), [sample: header], input)

下面的清单显示了如何侦听发送到的消息的输出:​​jms:output​

Message<?> receivedMessage = messaging.receive(outputTest)

收到的消息传递以下断言:

receivedMessage != null
assertJsons(receivedMessage.payload)
receivedMessage.headers.get(BOOK-NAME) == foo
场景 3(无输出的输入)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​jms:input​

messaging.send(new BookReturned(foo), [sample: header], delete)

4.7. 使用弹簧云流的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块为您提供了一种简单的方法 与春溪融合。对于提供的工件,它会自动下载 存根并注册所需的路由。

如果存根运行程序与流字符串的集成 首先解析为通道,不存在这样的通道, 目标解析为通道名称。​​messageFrom​​​​sentTo​​​​destination​​​​destination​


如果要使用 Spring Cloud Stream,请记住添加依赖项测试支持,如下所示:​​org.springframework.cloud:spring-cloud-stream​






马文

格拉德尔



<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>test</scope>
<classifier>test-binder</classifier>
</dependency>





4.7.1. 将运行器添加到项目中

您可以在 类路径。记得用注释你的测试类。​​@AutoConfigureStubRunner​

4.7.2. 禁用该功能

如果需要禁用此功能,请设置该属性。​​stubrunner.stream.enabled=false​

4.7.3. 例子

假设您有以下 Maven 存储库,其中包含为应用程序部署的存根:​​streamService​

└── .m2
└── repository
└── io
└── codearte
└── accurest
└── stubs
└── streamService
├── 0.0.1-SNAPSHOT
│ ├── streamService-0.0.1-SNAPSHOT.pom
│ ├── streamService-0.0.1-SNAPSHOT-stubs.jar
│ └── maven-metadata-local.xml
└── maven-metadata-local.xml

进一步假设存根包含以下结构:

├── META-INF
│ └── MANIFEST.MF
└── repository
├── accurest
│ ├── bookDeleted.groovy
│ ├── bookReturned1.groovy
│ └── bookReturned2.groovy
└── mappings

考虑以下合同(编号为 1 和 2):

Contract.make 
label return_book_1
input triggeredBy(bookReturnedTriggered())
outputMessage
sentTo(returnBook)
body( "bookName" : "foo" )
headers header(BOOK-NAME, foo)

Contract.make 
label return_book_2
input
messageFrom(bookStorage)
messageBody([
bookName: foo
])
messageHeaders header(sample, header)

outputMessage
sentTo(returnBook)
body([
bookName: foo
])
headers header(BOOK-NAME, foo)

现在考虑以下 Spring 配置:

stubrunner.repositoryRoot: classpath:m2repo/repository/
stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
stubrunner.stubs-mode: remote
spring:
cloud:
stream:
bindings:
output:
destination: returnBook
input:
destination: bookStorage

server:
port: 0

debug: true

这些示例适用于三种方案:

  • 方案 1(无输入消息)
  • 场景 2(由输入触发的输出)
  • 场景 3(无输出的输入)
方案 1(无输入消息)

要从标签触发消息,请使用接口作为 遵循:​​return_book_1​​​​StubTrigger​

stubFinder.trigger(return_book_1)

以下示例演示如何侦听发送到通道 whoseis 的消息输出:​​destination​​​​returnBook​

Message<?> receivedMessage = messaging.receive(returnBook)

收到的消息传递以下断言:

receivedMessage != null
assertJsons(receivedMessage.payload)
receivedMessage.headers.get(BOOK-NAME) == foo
场景 2(由输入触发的输出)

由于路由已为您设置,因此您可以向 发送消息,如下所示:​​bookStorage​​​​destination​

messaging.send(new BookReturned(foo), [sample: header], bookStorage)

以下示例演示如何侦听发送到的消息的输出:​​returnBook​

Message<?> receivedMessage = messaging.receive(returnBook)

收到的消息传递以下断言:

receivedMessage != null
assertJsons(receivedMessage.payload)
receivedMessage.headers.get(BOOK-NAME) == foo
场景 3(无输出的输入)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​jms:output​

messaging.send(new BookReturned(foo), [sample: header], delete)

4.8. 使用 Spring AMQP 的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块提供了一种简单的方法 与Spring AMQP的兔子模板集成。对于提供的工件,它 自动下载存根并注册所需的路由。

集成尝试独立工作(即,不与正在运行的交互 RabbitMQ 消息代理)。它期望应用程序上下文和 将其用作名为的 Spring 启动测试。因此,它可以使用Mockito间谍 用于验证和检查应用程序发送的消息的功能。​​RabbitTemplate​​​​@SpyBean​

在消息使用者端,存根运行器认为是全注释的 应用程序上下文中的终结点和所有对象。​​@RabbitListener​​​​SimpleMessageListenerContainer​

由于消息通常发送到AMQP中的交易所,因此消息合约包含 交换名称作为目标。另一端的消息侦听器绑定到 队列。绑定将交换连接到队列。如果触发了消息协定,则 Spring AMQP 存根运行器集成在应用程序上下文中查找绑定 匹配此交换。然后它从 Spring 交易所收集队列并尝试 查找绑定到这些队列的消息侦听器。为所有匹配触发消息 消息侦听器。

如果需要使用路由密钥,可以使用消息标头传递它们。​​amqp_receivedRoutingKey​

4.8.1. 将运行器添加到项目中

您可以在类路径上同时拥有 Spring AMQP 和 Spring Cloud 合约存根运行程序,并且 设置属性。记得为您的测试类添加注释 跟。​​stubrunner.amqp.enabled=true​​​​@AutoConfigureStubRunner​

如果类路径上已有流和集成,则需要 通过设置属性来显式禁用它们。​​stubrunner.stream.enabled=false​​​​stubrunner.integration.enabled=false​

4.8.2. 例子

假设您有以下 Maven 存储库,其中包含为应用程序部署的存根:​​spring-cloud-contract-amqp-test​

└── .m2
└── repository
└── com
└── example
└── spring-cloud-contract-amqp-test
├── 0.4.0-SNAPSHOT
│ ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom
│ ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar
│ └── maven-metadata-local.xml
└── maven-metadata-local.xml

进一步假设存根包含以下结构:

├── META-INF
│ └── MANIFEST.MF
└── contracts
└── shouldProduceValidPersonData.groovy

然后考虑以下合同:

Contract.make 
// Human readable description
description Should produce valid person data
// Label by means of which the output message can be triggered
label contract-test.person.created.event
// input to the contract
input
// the contract will be triggered by a method
triggeredBy(createPerson())

// output message of the contract
outputMessage
// destination to which the output message will be sent
sentTo contract-test.exchange
headers
header(contentType: application/json)
header(__TypeId__: org.springframework.cloud.contract.stubrunner.messaging.amqp.Person)

// the body of the output message
body([
id : $(consumer(9), producer(regex("[0-9]+"))),
name: "me"
])

现在考虑以下 Spring 配置:

stubrunner:
repositoryRoot: classpath:m2repo/repository/
ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
stubs-mode: remote
amqp:
enabled: true
server:
port: 0
触发消息

要使用上一节中的协定触发消息,请使用接口,如 遵循:​​StubTrigger​

stubTrigger.trigger("contract-test.person.created.event")

消息的目的地为 ,因此 Spring AMQP 存根运行程序 集成查找与此交换相关的绑定,如以下示例所示:​​contract-test.exchange​

@Bean
public Binding binding()
return BindingBuilder.bind(new Queue("test.queue")).to(new DirectExchange("contract-test.exchange"))
.with("#");

绑定定义绑定调用的队列。结果,以下侦听器 定义与合约消息匹配和调用:​​test.queue​

@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter)
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("test.queue");
container.setMessageListener(listenerAdapter);

return container;

此外,以下带批注的侦听器匹配并被调用:

@RabbitListener(bindings = @QueueBinding(value = @Queue("test.queue"),
exchange = @Exchange(value = "contract-test.exchange", ignoreDeclarationExceptions = "true")))
public void handlePerson(Person person)
this.person = person;

消息直接交给与匹配相关联的方法。​​onMessage​​​​MessageListener​​​​SimpleMessageListenerContainer​

春季 AMQP 测试配置

为了避免Spring AMQP在我们的测试期间试图连接到正在运行的代理,我们 配置模拟。​​ConnectionFactory​

要禁用模拟,请设置以下属性:,如下所示:​​ConnectionFactory​​​​stubrunner.amqp.mockConnection=false​

stubrunner:
amqp:
mockConnection: false

4.9. 使用 Spring JMS 的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块提供了一种简单的方法 与Spring JMS集成。

集成假定您有一个正在运行的 JMS 代理实例(例如嵌入式代理)。​​activemq​

4.9.1. 将运行器添加到项目中

你需要在类路径上同时拥有 Spring JMS 和 Spring Cloud 合约存根运行程序。记得为您的测试类添加注释 跟。​​@AutoConfigureStubRunner​

4.9.2. 例子

假设存根结构如下所示:

├── stubs
├── bookDeleted.groovy
├── bookReturned1.groovy
└── bookReturned2.groovy

进一步假设以下测试配置:

stubrunner:
repository-root: stubs:classpath:/stubs/
ids: my:stubs
stubs-mode: remote
spring:
activemq:
send-timeout: 1000
jms:
template:
receive-timeout: 1000

现在考虑以下合同(我们将其编号为 1 和 2):

Contract.make 
label return_book_1
input
triggeredBy(bookReturnedTriggered())

outputMessage
sentTo(output)
body( "bookName" : "foo" )
headers
header(BOOK-NAME, foo)


Contract.make 
label return_book_2
input
messageFrom(input)
messageBody([
bookName: foo
])
messageHeaders
header(sample, header)


outputMessage
sentTo(output)
body([
bookName: foo
])
headers
header(BOOK-NAME, foo)


方案 1(无输入消息)

要触发来自标签的消息,我们使用接口,如下所示:​​return_book_1​​​​StubTrigger​

stubFinder.trigger(return_book_1)

接下来,我们要侦听发送到以下消息的输出:​​output​

TextMessage receivedMessage = (TextMessage) jmsTemplate.receive(output)

然后,收到的消息将传递以下断言:

receivedMessage != null
assertThatBodyContainsBookNameFoo(receivedMessage.getText())
receivedMessage.getStringProperty(BOOK-NAME) == foo
场景 2(由输入触发的输出)

由于路由已为您设置,因此您可以向目的地发送消息。​​output​

jmsTemplate.
convertAndSend(input, new BookReturned(foo), new MessagePostProcessor()
@Override
Message postProcessMessage(Message message) throws JMSException
message.setStringProperty("sample", "header")
return message

)

接下来,我们要监听发送到的消息的输出,如下所示:​​output​

TextMessage receivedMessage = (TextMessage) jmsTemplate.receive(output)

收到的消息将传递以下断言:

receivedMessage != null
assertThatBodyContainsBookNameFoo(receivedMessage.getText())
receivedMessage.getStringProperty(BOOK-NAME) == foo
场景 3(无输出的输入)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​output​

jmsTemplate.
convertAndSend(delete, new BookReturned(foo), new MessagePostProcessor()
@Override
Message postProcessMessage(Message message) throws JMSException
message.setStringProperty("sample", "header")
return message

)

4.10. 使用 Spring Kafka 的消费者端消息传递

Spring Cloud 合约存根运行器的消息传递模块提供了一种简单的方法 与春天的卡夫卡集成。

集成假定您有一个嵌入式 Kafka 代理的运行实例(通过依赖关系)。spring-kafka-test

4.10.1. 将运行器添加到项目中

你需要在类路径上有 Spring Kafka、Spring Kafka 测试(运行)和 Spring Cloud 合约存根运行器。记得为您的测试类添加注释 跟。​​@EmbeddedBroker​​​​@AutoConfigureStubRunner​

通过 Kafka 集成,为了轮询单个消息,我们需要在 Spring 上下文启动时注册一个消费者。这可能会导致这样一种情况:当您在使用者端时,存根运行程序可以为同一组 ID 和主题注册额外的使用者。这可能会导致只有一个组件实际轮询消息的情况。由于在使用者端,您同时拥有 Spring Cloud 合约存根运行程序和 Spring Cloud 合约验证程序类路径,因此我们需要能够关闭此类行为。这是通过 theflag 自动完成的,这会禁用联系人验证程序使用者注册。如果应用程序既是 Kafka 消息的使用者又是生成者,则可能需要手动将该属性切换为生成的测试的基类。​​stubrunner.kafka.initializer.enabled​​​​false​

如果您有多个 bean,则可以提供自己的 bean 类型,以返回您选择的 bean。​​KafkaTemplate​​​​Supplier<KafkaTemplate>​​​​KafkaTemplate​

4.10.2. 例子

假设存根结构如下所示:

├── stubs
├── bookDeleted.groovy
├── bookReturned1.groovy
└── bookReturned2.groovy

进一步假设以下测试配置(注意指向嵌入式代理的 IP 通过):​​spring.kafka.bootstrap-servers​​​​$spring.embedded.kafka.brokers​

stubrunner:
repository-root: stubs:classpath:/stubs/
ids: my:stubs
stubs-mode: remote
spring:
kafka:
bootstrap-servers: $spring.embedded.kafka.brokers
producer:
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
properties:
"spring.json.trusted.packages": "*"
consumer:
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
"spring.json.trusted.packages": "*"
group-id: groupId

如果您的应用程序使用非整数记录键,则需要相应地设置 and 属性,因为 Kafka 反序列化需要非空 记录键为整数类型。​​spring.kafka.producer.key-serializer​​​​spring.kafka.consumer.key-deserializer​

现在考虑以下合同(我们将其编号为 1 和 2):

Contract.make 
label return_book_1
input
triggeredBy(bookReturnedTriggered())

outputMessage
sentTo(output)
body( "bookName" : "foo" )
headers
header(BOOK-NAME, foo)


Contract.make 
label return_book_2
input
messageFrom(input)
messageBody([
bookName: foo
])
messageHeaders
header(sample, header)


outputMessage
sentTo(output)
body([
bookName: foo
])
headers
header(BOOK-NAME, foo)


方案 1(无输入消息)

要触发来自标签的消息,我们使用接口,如下所示:​​return_book_1​​​​StubTrigger​

stubFinder.trigger(return_book_1)

接下来,我们要侦听发送到以下消息的输出:​​output​

Message receivedMessage = receiveFromOutput()

然后,收到的消息将传递以下断言:

assert receivedMessage != null
assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload())
assert receivedMessage.getHeaders().get(BOOK-NAME) == foo
场景 2(由输入触发的输出)

由于路由已为您设置,因此您可以向目的地发送消息。​​output​

Message message = MessageBuilder.createMessage(new BookReturned(foo), new MessageHeaders([sample: "header",]))
kafkaTemplate.setDefaultTopic(input)
kafkaTemplate.send(message)
Message message = MessageBuilder.createMessage(new BookReturned(bar), new MessageHeaders([kafka_messageKey: "bar5150",]))
kafkaTemplate.setDefaultTopic(input2)
kafkaTemplate.send(message)

接下来,我们要监听发送到的消息的输出,如下所示:​​output​

Message receivedMessage = receiveFromOutput()
Message receivedMessage = receiveFromOutput()

收到的消息将传递以下断言:

assert receivedMessage != null
assert assertThatBodyContainsBookNameFoo(receivedMessage.getPayload())
assert receivedMessage.getHeaders().get(BOOK-NAME) == foo
assert receivedMessage != null
assert assertThatBodyContainsBookName(receivedMessage.getPayload(), bar)
assert receivedMessage.getHeaders().get(BOOK-NAME) == bar
assert receivedMessage.getHeaders().get("kafka_receivedMessageKey") == bar5150
场景 3(无输出的输入)

由于路由已为您设置,因此您可以向目的地发送消息,如下所示:​​output​

Message message = MessageBuilder.createMessage(new BookReturned(foo), new MessageHeaders([sample: "header",]))
kafkaTemplate.setDefaultTopic(delete)
kafkaTemplate.send(message)

5. 春云合约存根跑者

使用Spring Cloud合约验证程序时可能遇到的问题之一是 将生成的 WireMock JSON 存根从服务器端传递到客户端(或 各种客户)。在消息传递的客户端生成方面也是如此。

复制 JSON 文件并手动设置消息传递的客户端不在 问题。这就是我们引入春云合约存根运行器的原因。它可以 自动下载并运行存根。

5.1. 快照版本

您可以将其他快照存储库添加到构建文件中以使用快照 版本,每次成功构建后都会自动上传,如下所示:

<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>

5.2. 将存根发布为 JAR

将存根发布为 jar 的最简单方法是集中存根的保存方式。 例如,您可以将它们作为 jar 保存在 Maven 存储库中。

对于Maven和Gradle来说,设置已经准备好工作了。但是,您可以自定义 如果你愿意的话。

以下示例演示如何将存根发布为 jar:

<!-- First disable the default jar setup in the properties section -->
<!-- we dont want the verifier to do a jar for us -->
<spring.cloud.contract.verifier.skip>true</spring.cloud.contract.verifier.skip>

<!-- Next add the assembly plugin to your build -->
<!-- we want the assembly plugin to generate the JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>stub</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
<inherited>false</inherited>
<configuration>
<attach>true</attach>
<descriptors>
$/tmp/releaser-1667490065708-0/spring-cloud-contract/docs/src/assembly/stub.xml
</descriptors>
</configuration>
</execution>
</executions>
</plugin>

<!-- Finally setup your assembly. Below you can find the contents of src/main/assembly/stub.xml -->
<assembly
xmlns="http://maven.apache.org/plugins/mave

以上是关于Spring Cloud 合约功能的主要内容,如果未能解决你的问题,请参考以下文章

spring cloud 合约 - Feign Clients

Spring Cloud 合约功能

使用Spring Cloud合约进行消费者驱动的合同测试

如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url

在同一个项目中配置spring cloud合约和zuul代理

在非 Spring 项目中运行 Spring Cloud Contract 测试