В настоящее время у меня возникла проблема с тестированием потребителей RabbitMQ с помощью имитаций.Кажется, проблема в том, что один тестовый класс работает с контекстом приложения без каких-либо имитаций, как и ожидалось.Следующий тестовый класс, который нужно запустить, настраивает некоторые имитации, которые он ожидает от потребителей, однако, когда тест выполняется, и сообщение отправляется, и его получают немодированные потребители из контекста приложения, созданного для первого класса теста.В результате мой второй тест не пройден.
Вот первый тест:
@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));
}
}
Второй тест:
@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());
}
}
Потребитель:
@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);
}
}
}
Это поднимает два связанных вопроса:
- Как я должен правильно проводить тестирование бобов с потребителями весной?
- Похоже, что Spring создает новый ApplicationContext для каждого класса тестирования, о чем свидетельствует увеличение числа потребителей при последующих запусках теста.Похоже, что @MockBean влияет на ключ кэша ApplicationContext (см .: Пересмешивание и отслеживание компонентов в Spring Boot ) и, вероятно, объясняет, почему существует несколько контекстов приложения.Но как мне запретить потребителям в других устаревших контекстах приложения потреблять мои тестовые сообщения?
Я решил эту проблему здесь: RabbitMQ MockBean BugJar