본문으로 건너뛰기
Advertisement

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