본문으로 건너뛰기

16.5 Testcontainers를 이용한 완벽한 통합 테스트 환경

H2 인메모리 DB로 테스트를 짜면 실제 운영 DB(MySQL, PostgreSQL)와 SQL 문법 차이, 제약조건 차이 등으로 테스트가 통과해도 실제 환경에서 오류가 발생할 수 있습니다. Testcontainers 는 테스트 실행 시 실제 Docker 컨테이너를 기동하여 완벽히 동일한 DB 환경을 제공합니다.

1. 의존성 추가

testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:mysql' // 사용하는 DB에 맞게 선택

2. @SpringBootTest + Testcontainers 통합 테스트

@SpringBootTest
@Testcontainers
class OrderIntegrationTest {

// MySQL 8.0 Docker 컨테이너를 테스트 중 자동 기동/종료
@Container
static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");

// 컨테이너가 기동되면 스프링의 DB 연결 설정을 동적으로 교체
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", mysql::getJdbcUrl);
registry.add("spring.datasource.username", mysql::getUsername);
registry.add("spring.datasource.password", mysql::getPassword);
}

@Autowired
private OrderService orderService;

@Autowired
private UserRepository userRepository;

@Test
@DisplayName("주문 생성 후 DB에 정상적으로 저장되어야 한다.")
@Transactional
void 주문_생성_통합_테스트() {
// Given: 실제 DB에 유저 데이터 삽입
User user = userRepository.save(new User("test", "test@example.com"));

// When: 실제 DB를 사용하는 서비스 메서드 호출
Long orderId = orderService.createOrder(new CreateOrderRequest(user.getId(), 1L, 2));

// Then: 실제 DB에 저장됐는지 조회 검증
assertThat(orderId).isNotNull().isPositive();
}
}

3. Testcontainers + Redis

@Container
static GenericContainer<?> redis = new GenericContainer<>("redis:7.0")
.withExposedPorts(6379);

@DynamicPropertySource
static void configureRedis(DynamicPropertyRegistry registry) {
registry.add("spring.data.redis.host", redis::getHost);
registry.add("spring.data.redis.port", () -> redis.getMappedPort(6379));
}