Contents
see List개요
Testcontainers는 테스트 실행 시 Docker 컨테이너를 자동으로 시작하고 종료하여, 실제 인프라에 가까운 환경에서 통합 테스트를 수행할 수 있게 하는 라이브러리입니다. H2 같은 인메모리 DB 대신 실제 PostgreSQL을, MockServer 대신 실제 Redis나 Kafka를 사용하여 프로덕션과 동일한 조건에서 테스트합니다. Spring Boot 3.1부터 공식 지원이 시작되어, 설정이 대폭 간소화되었습니다.
핵심 개념
Container Lifecycle은 테스트 라이프사이클과 연동됩니다. 테스트 클래스가 시작될 때 컨테이너가 생성되고, 모든 테스트가 끝나면 자동으로 정리됩니다. @Testcontainers 어노테이션과 @Container 어노테이션으로 선언적 관리가 가능합니다.
Dynamic Properties는 컨테이너가 할당받은 랜덤 포트 등의 동적 정보를 Spring 프로퍼티로 주입하는 메커니즘입니다. @DynamicPropertySource나 Spring Boot 3.1+의 @ServiceConnection을 사용합니다.
Reusable Containers는 테스트 실행 간에 컨테이너를 재사용하여 테스트 속도를 높이는 기능입니다. 로컬 개발 환경에서 특히 유용합니다.
실전 예제
Spring Boot 3.1+ 스타일의 Testcontainers 설정입니다.
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
@ServiceConnection을 사용한 간편 설정 (Spring Boot 3.1+):
@SpringBootTest
@Testcontainers
class OrderRepositoryTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16-alpine");
@Container
@ServiceConnection
static GenericContainer<?> redis =
new GenericContainer<>("redis:7-alpine")
.withExposedPorts(6379);
@Autowired
private OrderRepository orderRepository;
@Test
void shouldSaveAndFindOrder() {
Order order = Order.builder()
.customerId("CUST-001")
.totalAmount(BigDecimal.valueOf(50000))
.status(OrderStatus.CREATED)
.build();
Order saved = orderRepository.save(order);
Optional<Order> found = orderRepository.findById(saved.getId());
assertThat(found).isPresent();
assertThat(found.get().getCustomerId()).isEqualTo("CUST-001");
assertThat(found.get().getTotalAmount())
.isEqualByComparingTo(BigDecimal.valueOf(50000));
}
}
공통 컨테이너 설정을 추상 클래스로 분리합니다.
@Testcontainers
public abstract class IntegrationTestBase {
@Container
@ServiceConnection
protected static final PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("testdb")
.withInitScript("schema.sql");
@Container
@ServiceConnection
protected static final KafkaContainer kafka =
new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.5.0")
);
@Container
@ServiceConnection
protected static final GenericContainer<?> redis =
new GenericContainer<>("redis:7-alpine")
.withExposedPorts(6379);
}
// 실제 테스트 클래스
@SpringBootTest
class OrderIntegrationTest extends IntegrationTestBase {
@Autowired private OrderService orderService;
@Autowired private KafkaTemplate<String, OrderEvent> kafkaTemplate;
@Test
void shouldProcessOrderAndPublishEvent() {
OrderRequest request = new OrderRequest("CUST-001",
List.of(new ItemRequest("PROD-001", 2)));
Order order = orderService.createOrder(request);
assertThat(order.getStatus()).isEqualTo(OrderStatus.CREATED);
// Kafka 메시지 발행 확인
// ...
}
}
개발 환경에서 Testcontainers를 DevService로 활용합니다.
// src/test/java 하위에 TestApplication 정의
@TestConfiguration(proxyBeanMethods = false)
public class TestContainerConfig {
@Bean
@ServiceConnection
PostgreSQLContainer<?> postgresContainer() {
return new PostgreSQLContainer<>("postgres:16-alpine")
.withReuse(true); // 컨테이너 재사용
}
@Bean
@ServiceConnection
GenericContainer<?> redisContainer() {
return new GenericContainer<>("redis:7-alpine")
.withExposedPorts(6379)
.withReuse(true);
}
}
// 테스트용 main 메서드 - ./gradlew bootTestRun
public class TestApplication {
public static void main(String[] args) {
SpringApplication.from(Application::main)
.with(TestContainerConfig.class)
.run(args);
}
}
활용 팁
- 컨테이너 재사용:
~/.testcontainers.properties에testcontainers.reuse.enable=true를 설정하면 로컬에서 컨테이너를 재사용하여 테스트 속도를 크게 향상시킵니다. - CI 환경: GitHub Actions, GitLab CI 등에서는 Docker-in-Docker 또는 호스트 Docker 소켓 마운트가 필요합니다.
- 초기 데이터:
withInitScript()로 스키마와 초기 데이터를 설정하거나, Flyway/Liquibase 마이그레이션을 자동 실행하세요. - 병렬 테스트: 각 테스트 클래스가 독립된 컨테이너를 사용하면 병렬 실행 시 격리가 보장됩니다.
- Wait Strategy: 컨테이너 준비 상태를 정확히 감지하기 위해
withStartupTimeout()과 커스텀 WaitStrategy를 설정하세요.
마무리
Testcontainers는 "테스트 환경은 프로덕션과 같아야 한다"는 원칙을 실현합니다. H2와 목 객체에 의존하던 시대를 지나, 이제는 실제 PostgreSQL, Redis, Kafka를 테스트에서 그대로 사용할 수 있습니다. Spring Boot 3.1+의 @ServiceConnection 덕분에 설정도 매우 간단합니다. 통합 테스트의 신뢰성을 높이고 싶다면, Testcontainers 도입을 강력히 추천합니다.
spring
| No | 작성일 | Title |
|---|---|---|
| 2355 | 2026. 04. 07. | Spring Boot 3.4 RestClient 완벽 가이드 - WebClient를 대체하는 동기 HTTP 클라이언트 |
| 2338 | 2026. 04. 06. | Spring Boot 3.4 Virtual Threads 실전 적용 가이드 - 설정부터 성능 최적화까지 |
| 2323 | 2026. 04. 05. | Spring Boot 4.0 + Spring Framework 7 핵심 변경사항과 마이그레이션 가이드 |
| 2300 | 2026. 04. 05. | Spring Security 7 One-Time Token 로그인과 Passkey 인증 구현 가이드 |
| 2299 | 2026. 04. 05. | Spring Boot 3.5 WebClient 글로벌 설정과 SSL 자동 구성 완벽 가이드 |
| 2273 | 2026. 04. 04. | Spring Security 6 JWT 인증 완벽 구현: SecurityFilterChain부터 리프레시 토큰까지 |
| 2271 | 2026. 04. 04. | Spring Boot 3.3 + Virtual Threads 실전 적용: 설정부터 성능 튜닝까지 |
| 2196 | 2026. 02. 11. | Spring CRaC로 애플리케이션 시작 시간 최적화 |
| 2195 | 2026. 02. 11. | Spring gRPC로 마이크로서비스 통신 구현하기 |
| 2194 | 2026. 02. 11. | Spring Observability: Micrometer와 Grafana 통합 모니터링 |