Testcontainers로 DB 통합 테스트 완벽 구축: Docker 없이 자동 실행하는 실전 예제 가이드
백엔드 개발에서 테스트는 선택이 아니라 필수입니다. 특히 DB와 연동되는 비즈니스 로직은 단순 단위 테스트로 검증하기 어렵기 때문에, 실제 DB를 띄워 통합 테스트를 수행해야 신뢰할 수 있는 결과를 얻을 수 있습니다.
과거에는 개발자가 직접 Docker로 PostgreSQL이나 MySQL을 띄우고 테스트 환경을 관리해야 했습니다. 하지만 이제는 Testcontainers를 사용하면 테스트 실행 시 자동으로 Docker 기반의 DB 컨테이너를 띄우고, 테스트 종료 후 정리까지 자동으로 처리할 수 있습니다.
이 글에서는 초보 개발자도 Testcontainers를 처음부터 끝까지 이해할 수 있도록, PostgreSQL을 기준으로 통합 테스트 환경을 구축하는 방법을 실전 코드 중심으로 정리해드립니다.

1. Testcontainers란 무엇인가?
Testcontainers는 JUnit 기반 테스트 환경에서 Docker 컨테이너를 자동으로 실행하는 라이브러리입니다. 테스트 시작 시 컨테이너가 켜지고, 테스트 종료 시 자동으로 종료되기 때문에, 개발자는 별도로 Docker 명령을 실행하지 않아도 됩니다.
특징은 다음과 같습니다.
- PostgreSQL, MySQL, Redis 등 다양한 DB를 테스트용으로 자동 실행
- JUnit5와 완벽한 연동
- 테스트 간 데이터 격리 쉬움
- 로컬 환경 오염 없음
- CI 서버(GitHub Actions 등)에서도 그대로 실행 가능
이제 더 이상 “로컬 DB 설정 오류”, “버전 차이로 인한 테스트 실패” 같은 문제를 신경 쓸 필요가 없습니다.
2. Gradle 의존성 설정
Spring Boot + JUnit5 환경에서 Testcontainers를 사용하려면 다음 의존성을 추가합니다.
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:postgresql'
여기까지 끝나면 Testcontainers를 사용할 준비가 완료됩니다.
3. PostgreSQL 컨테이너 테스트 환경 구성
아래 코드는 Testcontainers에서 가장 많이 사용하는 패턴입니다: PostgreSQLContainer 객체를 정적(static)으로 선언하고, 테스트 시작 전에 자동으로 구동되도록 하는 방식입니다.
@Testcontainers
@SpringBootTest
public class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Autowired
private UserRepository userRepository;
@DynamicPropertySource
static void registerPgProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void 사용자저장_테스트() {
User user = new User("hani", "hani@test.com");
userRepository.save(user);
List users = userRepository.findAll();
assertFalse(users.isEmpty());
}
}
위 코드는 DB 컨테이너를 직접 실행하지 않아도, 테스트를 실행하는 순간 자동으로 PostgreSQL 컨테이너가 켜지고 DB 설정이 스프링에 자동 주입됩니다.

4. @DynamicPropertySource로 Spring Boot 설정 자동 주입하기
Spring Boot는 application.yml의 DB 설정을 그대로 읽습니다. 하지만 Testcontainers는 테스트마다 새로운 컨테이너를 띄우기 때문에, JDBC URL이 고정될 수 없습니다.
그래서 네 가지 정보를 동적으로 주입해야 합니다.
- spring.datasource.url
- spring.datasource.username
- spring.datasource.password
- spring.datasource.driver-class-name
이 모든 정보는 컨테이너에서 자동 생성되기 때문에 DynamicPropertySource로 스프링에게 연결 정보를 동적으로 넘겨줍니다.
5. 통합 테스트에서 가장 흔한 오류와 해결법
Testcontainers를 사용하다 보면 초급 개발자가 자주 겪는 오류들이 있습니다. 이를 정리하면 다음과 같습니다.
■ Docker가 아예 실행되지 않는 경우
→ Docker Desktop을 켜지 않은 경우가 가장 많습니다.
■ 포트 충돌 오류
→ Testcontainers는 기본적으로 랜덤 포트를 사용하지만, 특정 OS 환경에서는 충돌이 발생할 수 있습니다.
■ 테스트 속도 느림
→ 첫 실행 시 이미지를 다운로드하기 때문에 시간이 걸립니다. 그 후에는 매우 빠릅니다.
■ 다른 테스트와 격리 문제
→ static 컨테이너를 사용하면 속도는 빨라지지만 테스트 간 데이터가 완전히 격리되지 않을 수 있습니다.
필요하다면 @BeforeEach에서 데이터 초기화가 필요합니다.
6. 테스트 속도 최적화 전략
Testcontainers는 기본적으로 컨테이너를 매 테스트마다 새로 생성하기 때문에 속도가 느릴 수 있습니다. 아래와 같은 방식으로 최적화할 수 있습니다.
■ static 컨테이너 사용
테스트 클래스 전체에서 동일 컨테이너를 공유하여 속도를 극대화합니다.
■ 이미지 버전 고정
매번 다른 버전으로 다운로드하지 않도록 “postgres:15” 등 명시적인 버전 사용
■ 테스트 클래스 분리
DB 통합 테스트는 별도의 디렉토리로 분리하여 build 전체 속도 개선
■ Reusable 컨테이너 옵션
계속 재사용되는 설정을 켜면 전체 테스트 속도가 크게 향상됩니다.
7. 실전 예시: UserService 통합 테스트
Repository만 테스트하는 수준에서 벗어나 Service 레이어까지 통합 테스트를 구성하는 예제를 살펴보겠습니다.
@SpringBootTest
@Testcontainers
public class UserServiceTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15");
@Autowired
private UserService userService;
@DynamicPropertySource
static void configure(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void 회원가입_정상저장() {
User user = userService.register("joy", "joy@test.com");
assertNotNull(user.getId());
}
}
이 예제는 DB → Repository → Service → 트랜잭션까지 전체 흐름을 테스트하는 구조로, 실제 운영 환경에서 발생할 수 있는 다양한 오류를 미리 잡아낼 수 있습니다.

8. Testcontainers는 개발자의 테스트 문화를 바꾼다
Testcontainers는 단순히 DB를 띄우는 도구가 아니라, 테스트 환경의 ‘표준화’를 만들어주는 강력한 프레임워크입니다.
■ 모든 개발자가 같은 버전의 DB에서 테스트
■ 로컬 환경 오염 없음
■ CI/CD에서도 동일하게 실행
■ 데이터 격리 안정적
■ 통합 테스트 비용 크게 감소
운영 환경과 거의 동일한 구조를 테스트 코드에서 재현할 수 있기 때문에, 테스트의 신뢰도는 3배 이상 높아지고 전체 개발 품질도 향상됩니다.
Testcontainers를 익히는 것은 초급 개발자가 빠르게 성장하는 데 매우 중요한 투자입니다.
'배포·CI,CD·클라우드' 카테고리의 다른 글
| 클라우드 환경에서의 비용 효율화 — AWS/GCP 비용 줄이는 실무 전략 (0) | 2025.11.21 |
|---|---|
| Harbor 레지스트리 + Cosign 서명 + Trivy 스캔 + 배포 차단 정책(OPA/Kyverno)으로 컨테이너 공급망 보안 완성 (0) | 2025.11.03 |
| Velero로 Kubernetes 백업·복구: S3/MinIO 연동, PV 스냅샷, 네임스페이스 단위 복원 (0) | 2025.11.02 |
| External Secrets로 시크릿 자동 주입: AWS Secrets Manager/KMS · Kubernetes 네이티브 시크릿 관리 (1) | 2025.11.01 |
| Argo CD로 GitOps 파이프라인 구축: App-of-Apps, 환경 분리, 자동 동기화/PR 기반 승격 (0) | 2025.11.01 |