I'm trying to create a Spring Cloud Contract to test messages when using Spring Cloud Stream. I've included the dependencies in pom.xml
<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>
and configured the contracts plugin
<!-- Contracts -->
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>com.example.streams.kafkastreamer.KafkaStreamerApplicationTests
</baseClassForTests>
</configuration>
</plugin>
Then I've ran a simple application locally in order to check that everything is working as expected. However, after creating a Spring Cloud Contract test following the documentation I'm getting the following error while running the generated test
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'uppercase-out-0' is expected to be of type 'org.springframework.messaging.PollableChannel' but was actually of type 'org.springframework.cloud.stream.messaging.DirectWithAttributesChannel'
I've checked that the created test looks like the one at the documentation, and it kinda does it to me
@Test
public void validate_consume() throws Exception {
// given:
ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
"[\"MIAU\"]"
, headers()
.header("sample", "header")
);
// when:
contractVerifierMessaging.send(inputMessage, "uppercase-in-0");
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("uppercase-out-0");
assertThat(response).isNotNull();
// and:
assertThat(response.getHeader("contentType")).isNotNull();
assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json");
// and:
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
assertThatJson(parsedJson).field("['attributes']").field("['id']").isEqualTo("com.example.streams.kafkastreamer.KafkaStreamerApplication$$EnhancerBySpringCGLIB$$cf6cc14c2020-03-05T12:07:05.366");
assertThatJson(parsedJson).field("['attributes']").field("['source']").isEqualTo("file:///com/example/streams/kafkastreamer");
assertThatJson(parsedJson).field("['attributes']").field("['specversion']").isEqualTo("1.0");
assertThatJson(parsedJson).field("['attributes']").field("['type']").isEqualTo("My.test.event.type");
assertThatJson(parsedJson).field("['attributes']").field("['datacontenttype']").isEqualTo("application/json");
assertThatJson(parsedJson).field("['attributes']").field("['dataschema']").isNull();
assertThatJson(parsedJson).field("['attributes']").field("['subject']").isNull();
assertThatJson(parsedJson).field("['attributes']").field("['time']").isNull();
assertThatJson(parsedJson).field("['data']").field("['value']").isEqualTo("MIAU");
assertThatJson(parsedJson).field("['dataBase64']").isNull();
assertThatJson(parsedJson).field("['extensions']").field("['specversion']").isEqualTo("1.0");
assertThatJson(parsedJson).array("['extensionsFormats']").isEmpty();
}
In the Spring Cloud Contract documentation sample, jms is being used and the channel is set as sentTo('jms:output')
. Since I'm using a Spring Cloud Stream Binder I'm setting the name of the channel according to the definition o my binder as sentTo('uppercase-out-0')
. Here is my application properties
#stubrunner.integration.enabled: false To make sure is using Spring Cloud Stream
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.function.definition=uppercase;consume
My question is, why is the channel uppercase-out-0 not implementing a requiered PollableChannel? I guess I misunderstood something from the official documenation either from Spring Cloud Stream or from Spring Cloud Contract but cannot realise what.
Just a few more info. My guess is that autoconfiguration is configuring a bean of type SpringIntegrationSubMessages
but should be StreamStubMessages
. However, I don't know how or why this is happening. Am I guessing right?
The problem was comming from my parent test class configuration. At some point my IDE suggest me adding a component scan because was not finding a bean for
@Autowired
private MessageVerifier verifier;
so I added @ComponentScan(basePackages={"org.springframework.cloud.contract.verifier.messaging"})
and ended up initializing some beans that made conditional beans in ContractVerifierStreamAutoConfiguration
not be configured, but SpringIntegrationSubMessages
. Found that reviewing that in the official documentation no @ComponentScan
was being include and I cleaned my code