0

I'm testing my Kafka Consumer in Spring Boot. My consumer are similar to the following

@Slf4j
@Component
@RequiredArgsConstructor
public class KafkaPaymentConsumer {

    private final PaymentInterface paymentInterface;

    @KafkaListener(topics = "#{'${kafka.topic.payment}'}",
                   groupId = "#{'${kafka.group-id}'}")
    public void consumePaymentEvents(PaymentEvent paymentEvent) {
            paymentInterface.handleReceiptPaymentReceivedEvent(paymentEvent);        
    }
}

And My test cases are similar to the following

@SpringBootTest
@EmbeddedKafka(brokerProperties = {"listeners=PLAINTEXT://localhost:9092"},
               partitions = 1,
               controlledShutdown = true)
class KafkaPaymentConsumerTest {

    @Autowired
    KafkaTemplate<String, PaymentEvent> kafkaTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${kafka.topic.payment}")
    private String paymentTopic;


    @SpyBean
    private KafkaPaymentConsumer kafkaPaymentConsumer;

    @SpyBean
    private PaymentInterface paymentInterface;

    @Captor
    ArgumentCaptor<PaymentEvent> paymentEventCaptor;

    private static File PAYMENT_EVENT_JSON = Paths.get("src", "test", "resources", "files",
                                                       "Payment.json").toFile();
    @Test
    @SneakyThrows
    @DirtiesContext
    void consumePaymentEvents() {
        PaymentEvent event = objectMapper.readValue(PAYMENT_EVENT_JSON,
                                                    PaymentEvent.class);
        kafkaTemplate.send(paymentTopic, "1", event);

        verify(kafkaPaymentConsumer, timeout(10000).times(1)).consumePaymentEvents(
                paymentEventCaptor.capture());
        PaymentEvent argument = paymentEventCaptor.getValue();

        verify(paymentInterface, timeout(10000).times(1)).handleReceiptPaymentReceivedEvent(any());
    }
}

the test works well, BUT when running a batch of tests at once, some tests fail ! ( only when I run many tests at the same time !! ) it seems that there is an issue in the context with @EmbeddedKafka

I got like theses log errors

Actually, there were zero interactions with this mock.

or a Timeout when trying to poll records from the broker

Any explanation or suggestion please

Smaillns
  • 2,540
  • 1
  • 28
  • 40

1 Answers1

1

Since you don’t use a @DirtiesContext on your test class to close an application context in the end, it is not a surprise that other tests for the same topic can steal data from you. See if you can clean up contexts as I explained, or consider to use different topics in different tests. I’d prefer the dirties context since it guarantees that no any extra resources in the memory to cause race conditions and surprises .

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • I already added @DirtiesContext to Test cases, I added it to the class and I tried to change the topic names but still have the same problem ! – Smaillns Aug 02 '22 at 07:25
  • 3
    Unless you have `spring.kafka.consumer.auto-offset-reset=earliest`, it is possible that the template sends the record before the consumer has subscribed. By default, consumers don't get records that already are in the topic (`latest` is the default). – Gary Russell Aug 02 '22 at 13:37
  • Yeah... You see, Gary, he said that tests pass in isolation. – Artem Bilan Aug 02 '22 at 13:42
  • Still have the same issue ! that's quite strange – Smaillns Aug 03 '22 at 13:45
  • Any chances to share the project with us to let us to reproduce? – Artem Bilan Aug 03 '22 at 13:47
  • @ArtemBilan you can find it here pls https://github.com/smaillns/springboot-mongo-kafka – Smaillns Aug 04 '22 at 13:28
  • 1
    Something is off in your config: ` value-serializer: fr.test.test.compute..config.kafka.KafkaEventSerializer`. I doubt it can start clearly with that `..` package... – Artem Bilan Aug 04 '22 at 14:06
  • Can the project be simplified without MongoDB? – Artem Bilan Aug 04 '22 at 14:07
  • 1
    You have an empty `CfrMsOverdueApplicationTests` which starts your consumers from the `main` and does not close an application context in the end. So, this one might be a culprit for "stealing" data from other tests. – Artem Bilan Aug 04 '22 at 14:12
  • it should be `value-serializer: fr.test.test.compute.config.kafka.KafkaEventSerializer` – Smaillns Aug 04 '22 at 15:30
  • 1
    Again: or remove that `CfrMsOverdueApplicationTests` since it is an empty `@SpringBootTest`. Or mark it with the `@DirtiesContext` as well. – Artem Bilan Aug 04 '22 at 15:33