본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

 

강의 요약

오늘 강의에서는 Spring for Kafka의 기본 개념과 구성 요소를 다루었다. Spring Kafka는 Apache Kafka와 Spring Framework를 통합하여 메시지 기반 애플리케이션을 구축할 수 있도록 지원한다. KafkaTemplate을 통한 메시지 발행, @KafkaListener를 사용한 메시지 소비, 그리고 이를 Spring Boot 환경에서 설정하는 방법을 학습했다. 그러면 테스트를 위해서는 어떻게해야할까? 알아보도록 하자

 

Spring Kafka 통합 테스트 전략

Kafka를 사용하는 애플리케이션을 개발할 때 가장 큰 과제 중 하나는 신뢰할 수 있는 테스트 환경을 구축하는 것이다. 외부 Kafka 브로커에 의존하면 테스트의 독립성과 재현성이 떨어질 수 있다. Spring Kafka Test는 이러한 문제를 해결하기 위해 두 가지 주요 접근 방식을 제공한다.

 

EmbeddedKafka를 활용한 테스트

의존성 설정

Spring Kafka Test 모듈은 테스트 환경에서 인메모리 Kafka 브로커를 실행할 수 있는 기능을 제공한다.

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka-test</artifactId>
    <version>3.1.1</version>
    <scope>test</scope>
</dependency>

테스트 구성

@EmbeddedKafka 어노테이션을 사용하면 테스트 실행 시 자동으로 Kafka 브로커가 시작된다.

@SpringBootTest
@DirtiesContext
@EmbeddedKafka(partitions = 1, brokerProperties = {
    "listeners=PLAINTEXT://localhost:9092",
    "port=9092"
})
class EmbeddedKafkaIntegrationTest {

    @Autowired
    private KafkaConsumer consumer;

    @Autowired
    private KafkaProducer producer;

    @Value("${test.topic}")
    private String topic;

    @Test
    public void givenEmbeddedKafkaBroker_whenSendingMessage_thenMessageReceived()
      throws Exception {
        String data = "Test message";

        producer.send(topic, data);

        boolean messageConsumed = consumer.getLatch().await(10, TimeUnit.SECONDS);
        assertTrue(messageConsumed);
        assertThat(consumer.getPayload(), containsString(data));
    }
}

  • @DirtiesContext 어노테이션은 각 테스트 간 컨텍스트를 격리하여 테스트 독립성을 보장한다.
  • partitions 속성은 토픽당 파티션 수를 지정하며, 테스트 환경에서는 단순성을 위해 1로 설정하는 것이 일반적이다.

 

컨슈머 설정의 핵심

테스트에서 중요한 설정은 auto-offset-reset: earliest이다. 이 설정은 컨슈머가 메시지를 읽기 시작하는 오프셋 위치를 지정한다. 테스트 환경에서는 컨테이너가 메시지 발송 이후에 시작될 수 있으므로, earliest로 설정하여 토픽의 처음부터 메시지를 읽도록 보장해야 한다.

 

Testcontainers를 활용한 테스트

Testcontainers의 필요성

EmbeddedKafka는 빠르고 가벼운 장점이 있지만, 실제 Kafka 브로커와 미묘한 차이가 있을 수 있다. 또한 포트 충돌 가능성도 존재한다. Testcontainers는 Docker 컨테이너로 실제 Kafka 브로커를 실행하여 이러한 한계를 극복한다.

의존성 추가

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>kafka</artifactId>
    <version>1.19.3</version>
    <scope>test</scope>
</dependency>

테스트 구성

@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class KafkaTestContainersTest {

    @ClassRule
    public static KafkaContainer kafka =
      new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3"));

    @Test
    public void givenKafkaDockerContainer_whenSendingMessage_thenMessageReceived()
      throws Exception {
        String data = "Test message";

        producer.send(topic, data);

        boolean messageConsumed = consumer.getLatch().await(10, TimeUnit.SECONDS);
        assertTrue(messageConsumed);
    }
}

동적 포트 바인딩 처리

Testcontainers는 포트 충돌을 방지하기 위해 동적으로 포트를 할당한다. 따라서 브로커 주소를 설정 파일에 하드코딩할 수 없다.

@Bean
public Map<String, Object> consumerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers());
    props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
    props.put(ConsumerConfig.GROUP_ID_CONFIG, "baeldung");
    return props;
}

@Bean
public ProducerFactory<String, String> producerFactory() {
    Map<String, Object> configProps = new HashMap<>();
    configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers());
    return new DefaultKafkaProducerFactory<>(configProps);
}

  • kafka.getBootstrapServers() 메서드는 컨테이너가 시작된 후 동적으로 할당된 포트 정보를 포함한 브로커 주소를 반환한다.

 

테스트 전략 선택 시 고려사항

EmbeddedKafka 선택이 적합한 경우

  • 빠른 테스트 실행 속도가 중요한 경우
  • Docker 환경이 제약되거나 사용할 수 없는 경우
  • 간단한 메시지 발행/소비 로직을 검증하는 경우
  • CI/CD 파이프라인에서 실행 시간을 최소화해야 하는 경우

Testcontainers 선택이 적합한 경우

  • 실제 프로덕션 환경과 최대한 유사한 테스트가 필요한 경우
  • Kafka의 특정 버전이나 설정을 정확히 재현해야 하는 경우
  • 복잡한 Kafka 설정이나 커스텀 플러그인을 테스트하는 경우
  • 다른 시스템과의 통합 테스트가 필요한 경우

 

두 방식 모두 외부 Kafka 브로커 의존성을 제거하여 테스트의 독립성과 재현성을 확보한다는 공통 목표를 가진다. 프로젝트의 요구사항, 테스트 복잡도, 실행 환경의 제약사항을 종합적으로 고려하여 적절한 방식을 선택하는 것이 중요하다.

 

 

참고 출처

 

 

시작 시간
종료 시간
학습 인증 - 디지털 필기
수강 인증

 

 

https://fastcampus.info/4oKQD6b

+ Recent posts