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));
}