이 글에서 얻는 것

  • 통합 테스트(Integration Test)가 왜 필요한지, 단위 테스트와 어떻게 역할을 나눌지 기준이 생깁니다.
  • Testcontainers로 MySQL/Redis/Kafka 같은 의존성을 “진짜로” 붙여서 테스트하는 기본 패턴을 익힙니다.
  • CI에서 느려짐/불안정(플레이키) 문제를 줄이는 운영 팁(이미지 고정, 재사용, 시드/정리)을 정리합니다.

0) 통합 테스트는 언제 필요할까

단위 테스트가 로직의 대부분을 커버해야 하지만, 다음 영역은 단위 테스트만으로 놓치기 쉽습니다.

  • DB 매핑/쿼리/트랜잭션 경계(JPA 동작)
  • Redis/Kafka 같은 외부 의존성과의 연결/설정
  • 마이그레이션(Flyway/Liquibase) 적용 여부

이런 것들은 “실제로 붙여보는 테스트”가 가장 빠르고 확실합니다.

1) Testcontainers가 해결하는 문제

Testcontainers는 테스트 실행 시 Docker 컨테이너를 올려서, 로컬/CI 어디서든 “비슷한 환경”을 재현할 수 있게 해줍니다.

  • 로컬에 DB를 설치하지 않아도 됨
  • CI에서도 동일한 버전의 DB/Redis/Kafka를 쓸 수 있음
  • “내 컴퓨터에서는 되는데 CI에서는 안 됨”을 줄여줌

2) 기본 패턴: 컨테이너 + DynamicPropertySource

@Testcontainers
@SpringBootTest
public class OrderServiceTest {

    @Container
    static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");

    @DynamicPropertySource
    static void datasourceProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", mysql::getJdbcUrl);
        registry.add("spring.datasource.username", mysql::getUsername);
        registry.add("spring.datasource.password", mysql::getPassword);
    }
}

핵심은:

  • 컨테이너는 테스트 시작 시 올라오고,
  • 실제 연결 정보(랜덤 포트 포함)를 스프링 설정으로 주입해,
  • 애플리케이션이 “진짜 DB”에 붙도록 만드는 것입니다.

3) 베스트 프랙티스(실무에서 자주 쓰는 것)

  • 정적 컨테이너로 테스트 클래스 간 재사용 → 성능 향상
  • 테스트 전용 프로필 분리, 마이그레이션 툴(Flyway/Liquibase) 함께 실행
  • Kafka/Redis도 동일 방식으로 등록, 네트워크 포트 충돌 주의

추가 팁:

  • 이미지 버전은 고정하세요(예: mysql:8.0.36). “latest”는 CI에서 갑자기 깨지기 쉽습니다.
  • 데이터 정리는 “테스트 격리”의 핵심입니다. 테스트마다 데이터를 초기화하는 전략(트랜잭션 롤백/테이블 truncate/새 스키마)을 정하세요.
  • 컨테이너 시작 시간이 부담이면:
    • 테스트 스코프를 좁히고(진짜 필요한 테스트만 컨테이너),
    • 컨테이너 재사용 전략을 고려합니다(환경/정책에 따라).

4) CI에서 주의할 점

  • CI가 Docker를 사용할 수 있는지 확인해야 합니다(권한/런타임).
  • 네트워크 제한/이미지 pull 제한이 있으면 미리 이미지 캐시(프리풀) 또는 사설 레지스트리를 고려합니다.
  • 테스트가 병렬로 돌 때 컨테이너/DB 상태가 섞이지 않도록(공유 상태) 설계를 주의합니다.

5) 자주 하는 실수

  • 통합 테스트를 너무 많이 만들어서 빌드가 느려지고, 결국 안 돌리게 됨
  • 이미지 버전이 흔들려 CI가 간헐적으로 깨짐
  • 데이터 시드/정리가 불완전해서 테스트가 순서에 의존(플레이키)

연습(추천)

  • @DataJpaTest + Testcontainers로 Repository 테스트를 하나 만들고, 로컬 H2와 어떤 차이가 있는지 확인해보기
  • Redis 컨테이너를 추가해 캐시 동작을 통합 테스트로 검증해보기(캐시 히트/미스)
  • CI에서 테스트가 느릴 때 어디가 병목인지(컨테이너 startup/pull/마이그레이션) 측정하고 개선 포인트를 정리해보기