I'm currently facing an issue with testing RabbitMQ consumers with mocks. The issue seems to be that one test class runs with an application context without any mocks, as expected. The next test class to run sets up some mocks that it expects the consumers to use, however when the test runs and a message is sent and it gets picked up by the non-mocked consumers from the application context created for the first test class. As a result my second test fails.
Here is the first test:
@SpringBootTest
public class DemoApplicationTests extends AbstractTestNGSpringContextTests {
@Autowired
private RabbitAdmin rabbitAdmin;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Test(priority = 1)
public void contextLoads() {
logger.info("=============== CONSUMERS: " + rabbitAdmin.getQueueProperties(USER_MESSAGING_QUEUE).get(RabbitAdmin.QUEUE_CONSUMER_COUNT));
}
}
Second test:
@SpringBootTest
public class UserServiceTests extends AbstractTestNGSpringContextTests {
@Autowired
private UserService userService;
@Autowired
private UserMessageConsumer userMessageConsumer;
@MockBean
@Autowired
private ThirdPartyUserDataClient thirdPartyUserDataClient;
@Autowired
private UserRepository userRepository;
@Autowired
private RabbitAdmin rabbitAdmin;
@Test(priority = 2)
public void createUpdateUserTest() {
logger.info("=============== CONSUMERS: " + rabbitAdmin.getQueueProperties(USER_MESSAGING_QUEUE).get(RabbitAdmin.QUEUE_CONSUMER_COUNT));
String additionalData = org.apache.commons.lang3.RandomStringUtils.random(5);
Mockito.when(thirdPartyUserDataClient.getAdditionalUserData(ArgumentMatchers.anyLong())).thenReturn(additionalData);
User user = new User();
user.setName("Test User");
user.setState(UserState.PENDING);
user = userService.createUser(user);
Assert.assertNotNull(user.getId());
User finalUser = user;
Awaitility.await().until(() -> {
User user2 = userService.getUserById(finalUser.getId());
return finalUser != null && additionalData.equals(user2.getAdditionalData());
});
user.setState(UserState.CREATED);
user = userService.updateUser(user);
Assert.assertEquals(UserState.CREATED, user.getState());
}
}
The consumer:
@Component
public class UserMessageConsumer {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String FAILED_TO_GET_ADDITIONAL_DATA = "FAILED_TO_GET_ADDITIONAL_DATA";
@Autowired
private UserService userService;
@Autowired
private ThirdPartyUserDataClient thirdPartyUserDataClient;
public void handleUserCreatedMessage(UserCreatedMessage userCreatedMessage) {
Long userId = userCreatedMessage.getUserId();
User user = userService.getUserById(userId);
if (user != null) {
String additionalData;
try {
additionalData = thirdPartyUserDataClient.getAdditionalUserData(userId);
logger.info("Successfully retrieved additional data [{}] for user [{}].", additionalData, userId);
} catch (HttpClientErrorException ex) {
additionalData = FAILED_TO_GET_ADDITIONAL_DATA;
logger.warn("Failed to retrieve additional data for user [{}].", userId, ex);
}
user.setAdditionalData(additionalData);
userService.updateUser(user);
}
}
}
This brings up two related questions:
I've bugjar'd this issue here: RabbitMQ MockBean BugJar
Add @DirtiesContext
to each test class to shut down the cached context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With