Как написать автотест с Kafka
Что проверяют
Умеете ли вы тестировать асинхронное взаимодействие: сообщение отправлено, но появляется в топике не мгновенно, и тест должен дождаться его без Thread.sleep. Следом спрашивают, откуда в тесте берётся Kafka и как не ловить чужие сообщения из общего топика.
Как отвечать
Сначала определите, что проверяете: сервис публикует событие после действия или сервис правильно обрабатывает входящее сообщение. От этого зависит, кто в тесте продюсер, а кто консьюмер.
Каркас на Java:
- окружение: Kafka в контейнере через Testcontainers (модуль
kafka) на время прогона, для Spring есть@EmbeddedKafkaизspring-kafka-test. Общий стенд тоже годится, но тогда уникальные топики или ключи на каждый тест; - продюсер:
send()асинхронный, поэтому ждут подтверждения черезsend(record).get()или вызываютflush(); - консьюмер: уникальный
group.idна прогон иauto.offset.reset=earliest, иначе новая группа начнёт с конца топика и не увидит сообщение, отправленное до подписки; - ожидание:
poll()в цикле до нужной записи или таймаута, удобно через Awaitility:await().atMost(Duration.ofSeconds(10)).untilAsserted(...); - проверка: найти своё сообщение по ключу или correlation id, затем сверить тело (десериализовать JSON и сравнить поля), заголовки и партицию, если важен порядок.
Для входящих сообщений логика обратная: отправляете событие и ждёте побочный эффект, то есть запись в базе, вызов заглушки в WireMock или ответное сообщение.
Где спотыкаются
Делают один poll на секунду и проверяют записи в forEach. Если сообщение не успело прийти, коллекция пустая, тело цикла не выполняется ни разу, и тест зелёный. Нужно явно утверждать, что запись найдена.
Ставят Thread.sleep вместо ожидания по условию. Тест медленный на быстрой машине и нестабильный на медленной.
Не изолируют данные: общий group.id и общий топик приводят к тому, что один тест вычитывает сообщения другого, и прогон падает случайно при параллельном запуске.