I’m having trouble implementing Spring Cloud Contract on the producer side to generate contracts for event triggering via RabbitMQ. I`m using spring-boot-starter-amqp as interface to RabbitMq.
The tests generated by the framework are failing with the following error:
NoSuchBeanDefinitionException: No bean named 'car-interest-ex' available
My contract (Groovy DSL) is defined as follows:
Contract.make {
description 'Should trigger message about interest in a car'
label 'car_interest'
input {
triggeredBy('carInterestTriggered()')
}
outputMessage {
sentTo("car-interest-ex")
headers {
header("amqp_receivedRoutingKey", "")
}
body([
carId : 1,
event: "CAR_INTEREST"
])
}
}
This resulted in the following test provided by the framework:
@SuppressWarnings("rawtypes")
public class GeneralTest extends GeneralBase {
@Inject ContractVerifierMessaging contractVerifierMessaging;
@Inject ContractVerifierObjectMapper contractVerifierObjectMapper;
@Test
public void validate_sendCarInterestMessage() throws Exception {
// when:
carInterestTriggered();
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("car-interest-ex",
contract(this, "sendCarInterestMessage.yml"));
assertThat(response).isNotNull();
// and:
assertThat(response.getHeader("amqp_receivedRoutingKey")).isNotNull();
assertThat(response.getHeader("amqp_receivedRoutingKey").toString()).isEqualTo("");
// and:
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload()));
assertThatJson(parsedJson).field("['carId']").isEqualTo(1);
assertThatJson(parsedJson).field("['event']").isEqualTo("CAR_INTEREST");
}
}
My test base class is configured as follows:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@AutoConfigureMessageVerifier
public class GeneralBase extends BaseContractTest {
@Autowired
CarPublisher carPublisher;
@Autowired
Exchange exchange;
@Autowired
RabbitTemplate rabbitTemplate;
public void carInterestTriggered() {
var payload = CarInterestPayload.create(String.valueOf(1));
carPublisher.sendMessage(payload);
}
}
My Publisher is written as follows:
@Component
@Log4j2
public class CarPublisher {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private Exchange exchange;
public void sendMessage(CarInterestPayload payload) {
try {
log.info("payload send: %s".formatted(payload));
rabbitTemplate.convertAndSend(exchange.getName(),"", payload);
} catch (Exception e) {
log.error("message not send: %s".formatted(payload));
}
}
}
And finally, my Rabbit configuration is as follows:
@Configuration
public class RabbitMqProducerConfig {
static final String exchange = "car-interest-ex";
@Bean
public Exchange directExchangeCarInterest() {
return new DirectExchange(exchange);
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
var template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(messageConverter());
return template;
}
@Bean
public Jackson2JsonMessageConverter messageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return new Jackson2JsonMessageConverter(objectMapper);
}
}
Here are the dependencies I am using:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>4.1.0</version>
<extensions>true</extensions>
<configuration>
<packageWithBaseClasses>com.tech.community.cars.contract</packageWithBaseClasses>
</configuration>
</plugin>
The versions are:
spring boot version:3.2.3
spring cloud version: 2023.0.0
spring cloud contract version:4.1.0
spring amqp version: 3.2.3
java: 17
When I run mvn clean install, the tests fail as mentioned above with the error NoSuchBeanDefinitionException: No bean named 'car-interest-ex' available.
The stack trace of the error is as follows:
2024-07-24 17:42:18,938 ERROR main o.s.c.c.v.m.i.SpringIntegrationStubMessages:74 - Exception occurred while trying to read a message from a channel with name [car-interest-ex]
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car-interest-ex' available
...
java.lang.IllegalStateException: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car-interest-ex' available
at org.springframework.cloud.contract.verifier.messaging.integration.SpringIntegrationStubMessages.receive(SpringIntegrationStubMessages.java:76)
at org.springframework.cloud.contract.verifier.messaging.integration.SpringIntegrationStubMessages.receive(SpringIntegrationStubMessages.java:82)
at org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration$2.receive(ContractVerifierIntegrationConfiguration.java:84)
at org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration$2.receive(ContractVerifierIntegrationConfiguration.java:75)
at org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging.receive(ContractVerifierMessaging.java:72)
at com.tech.community.cars.contract.GeneralTest.validate_sendCarInterestMessage(GeneralTest.java:30)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car-interest-ex' available
Could you please help me understand where the error is? What do I need to do to successfully run the tests on the Producer side?
I have already tried changing the RabbitMQ configurations, binding the queue on the producer side. I also looked for information in the Spring Cloud Contract documentation, but I couldn’t make any progress.
Thiago Otoni is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.