标题翻译
Contract testing messages in a Flux in Spring Cloud Stream gives IllegalArgumentException Message must not be null
问题
我正在尝试使用Spring Cloud Stream和Spring Cloud Contract对从端点发出的事件流进行契约测试。但是,当我运行我的测试时,我得到一个IllegalArgumentException
,详细信息是Message must not be null
。换句话说,我在我的消息接收器上没有收到任何消息。我的Spring Cloud版本是Hoxton。我在我的pom中添加了以下依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<!--TEST -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>test</scope>
<classifier>test-binder</classifier>
</dependency>
我已经按照这里的示例配置了一个新的绑定,链接在此。当我运行应用程序并发送curl -X POST localhost:8080
请求时,它可以正常工作。
application.properties
文件:
stubrunner.stream.enabled=true
spring.cloud.stream.bindings.uppercase-in-0.destination=test
spring.cloud.stream.bindings.uppercase-in-0.group=testGroup
spring.cloud.stream.bindings.uppercase-out-0.destination=hood
spring.cloud.stream.bindings.consume-in-0.destination=hood
spring.cloud.stream.bindings.consume-out-0.destination=downtown
spring.cloud.stream.bindings.supplier-out-0.destination=test
spring.cloud.function.definition=uppercase;consume;supplier
控制器:
@PostMapping(value = "/")
public void handlePost() {
Faker faker = new Faker();
Message<String> message = MessageBuilder.withPayload(faker.chuckNorris().fact()).build();
EventSupplier.processor.onNext(message);
}
Bean定义:
@Configuration
public class EventSupplier {
public static final EmitterProcessor<Message<String>> processor = EmitterProcessor.create();
@Bean
public Supplier<Flux<Message<String>>> supplier() {
return () -> processor;
}
}
合同基础测试类:
@ActiveProfiles("test")
@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureMessageVerifier
@EnableBinding(KafkaStreamerApplication.class)
public abstract class KafkaStreamerApplicationTests {
@Autowired
private DummyController dummyController;
public void supply() {
dummyController.handlePost();
}
}
契约:
org.springframework.cloud.contract.spec.Contract.make {
label 'some_label'
input {
triggeredBy("supply()")
}
outputMessage {
sentTo('supplier-out-0')
body(
anyNonBlankString()
)
headers {
messagingContentType(applicationJson())
}
}
}
我尝试过创建函数和消费者的合同,两者都有效。我还尝试过使用类型为String
的供应商,而不是Flux<Message<String>>
,也可以工作。你可以查看上面代码中的注释行。
在调试过程中,我发现在StreamMessageCollectorMessageReceiver
中,在检索MessageChannel
bean时,当调用receive("supplier-out-0", 5, "SECONDS")
方法时,我得到的是一个DirectWithAttributesChannel
实例。此外,在查看文档时,我发现了一个MessageChannel
的实现,对我来说,它看起来是应该被实例化的候选对象 FluxMessageChannel
。
我猜想,Spring Cloud Contract正在等待将消息直接发送到队列中(DirectWithAttributesChannel
),但由于Flux已经在队列中,我只是更新了Flux的内容,这意味着没有消息被推送到队列中(FluxMessageChannel
?),因此没有消息被接收到(null
),这就是为什么在运行测试时会出现IllegalArgumentException
和详细错误信息Message must not be null
的原因。
我的配置中是否缺少什么?这种情况是否可以通过合同进行测试?使用合同来测试这种情况是否是一种不好的方法?
英文翻译
I'm trying to contract test a Flux of events emitted from an endpoint using Spring Cloud Stream and Spring Cloud Contract. However, I'm getting an IllegalArgumentException
with detailMessage Message must not be null
when running my test. Or in other words I'm not receiving any messages on my message receiver. My spring cloud version is Hoxton. I've added the following dependencies in my pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<!--TEST -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>test</scope>
<classifier>test-binder</classifier>
</dependency>
I've configured a new binding following the samples here. Is working properly when I run the app and I send a curl -X POST localhost:8080
request.
application.properties
stubrunner.stream.enabled=true
spring.cloud.stream.bindings.uppercase-in-0.destination=test
spring.cloud.stream.bindings.uppercase-in-0.group=testGroup
spring.cloud.stream.bindings.uppercase-out-0.destination=hood
spring.cloud.stream.bindings.consume-in-0.destination=hood
spring.cloud.stream.bindings.consume-out-0.destination=downtown
spring.cloud.stream.bindings.supplier-out-0.destination=test
spring.cloud.function.definition=uppercase;consume;supplier
Controller
@PostMapping(value = "/")
public void handlePost() {
Faker faker = new Faker();
Message<String> message = MessageBuilder.withPayload(faker.chuckNorris().fact()).build();
// supplier.get();
EventSupplier.processor.onNext(message);
}
Bean definition
@Configuration
public class EventSupplier {
public static final EmitterProcessor<Message<String>> processor = EmitterProcessor.create();
@Bean
// public Supplier<String> supplier() {
public Supplier<Flux<Message<String>>> supplier() {
// return () -> "";
return () -> processor;
}
}
Contracts Base test
@ActiveProfiles("test")
@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureMessageVerifier
@EnableBinding(KafkaStreamerApplication.class)
public abstract class KafkaStreamerApplicationTests {
@Autowired
private DummyController dummyController;
public void supply() {
dummyController.handlePost();
}
}
Contract
org.springframework.cloud.contract.spec.Contract.make {
label 'some_label'
input {
triggeredBy("supply()")
}
outputMessage {
sentTo('supplier-out-0')
body(
anyNonBlankString()
)
headers {
messagingContentType(applicationJson())
}
}
}
I've tried creating contracts for function and consumer and both worked. I've also tried using a supplier of type String
instead of Flux<Message<String>>
and worked too. You can look at the commented lines at the code above.
While debugging I've seen that in StreamMessageCollectorMessageReceiver
I'm getting a DirectWithAttributesChannel
instance when retrieving the MessageChannel
bean at receive("supplier-out-0", 5, "SECONDS")
method. Also while looking into the documentation I've found a MessageChannel
implementation that, to me, looks like a candidate to be the one should have been instantiated FluxMessageChannel
.
My guess is that spring cloud contract is waiting for a message to be sent into the queue directly(DirectWithAttributesChannel
) but since the flux is already in the queue and I'm just updating the flux content, it means that not message is pushed into the queue(FluxMessageChannel
?) so no message is received(null
) and that's why I'm getting an IllegalArgumentException
with details Message must not be null
error when running my tests.
Is there something missing in my configuration? Can this scenario be tested by contracts? Is a bad approach to test this by using contracts?
专注分享java语言的经验与见解,让所有开发者获益!
评论