[Test] 테스트 컨테이너 설정
서론
테스트 시 데이터베이스을 사용하는 상황이 존재한다. 자바/스프링 환경에서는 보통 가벼운 h2 데이터베이스를 사용한다. h2 데이터베이스 는 인메모리/임베디드 모드를 지원하여 테스트(실행) 시 h2 DB 는 같이 뜨고 테스트 종료 시 같이 종료된다.
하지만, 필요에 따라 실제 운영 환경에서 사용하는 데이터베이스의 기능이 필요할 때가 있다. 테스트 시 동작해야 하는 DB는 h2 가 아닌 실제 운영 환경에서 사용되는 DB 이다. 이런 상황에서 고려할 수 있는 것이 테스트 컨테이너이다.
테스트 컨테이너란
도커와 같은 컨테이너 기반으로 프로세스를 격리하는 오픈 소스를 사용하면 실제 운영환경에서 사용하는 DB 를 사용할 수 있다. 테스트 컨테이너란 도커 컨테이너를 기반으로 일회용의, 가벼운 여러 인스턴스를 띄울 수 있는 오픈 소스 라이브러이다. 공식 홈페이지에서 작성된 설명은 다음과 같다.
Testcontainers is an open source library for providing throwaway, lightweight instances of databases, message brokers, web browsers, or just about anything that can run in a Docker container.
도커를 사용하기 때문에 전제조건은 도커가 테스트 환경에 깔려 있어야 한다.
사용 방법
build.gradle 에 다음의 의존성을 추가한다.
testImplementation 'org.testcontainers:junit-jupiter' # 공통
testImplementation 'org.testcontainers:mysql' # 컨테이너로 띄울 인프라에 대한 의존성을 추가한다.
기본적인 동작은 다음과 같다.
static MySQLContainer<?> mysql = new MySQLContainer<>(
DockerImageName.parse("ubuntu/mysql:edge").asCompatibleSubstituteFor("mysql"));
각 원하는 인프라에 대한 컨테이너 객체를 생성한다. 생성하는 방법은 해당 의존성을 추가했을 때 관련 컨테이너 클래스가 추가된다.
static{
mysql.start();
}
해당 컨테이너를 실행시킨다.
@BeforeAll
static void beforeAll(){
System.setProperty("spring.datasource.url", mysql.getJdbcUrl());
System.setProperty("spring.datasource.username", mysql.getUsername());
System.setProperty("spring.datasource.password", mysql.getPassword());
}
각 인프라와 관련된 설정 값을 시스템 프로퍼티로 등록한다.
public class TestContainerConfig {
static MySQLContainer<?> mysql = new MySQLContainer<>(
DockerImageName.parse("ubuntu/mysql:edge").asCompatibleSubstituteFor("mysql"));
static{
mysql.start();
}
@BeforeAll
static void beforeAll(){
System.setProperty("spring.datasource.url", mysql.getJdbcUrl());
System.setProperty("spring.datasource.username", mysql.getUsername());
System.setProperty("spring.datasource.password", mysql.getPassword());
}
}
제가 테스트 컨테이너를 구현한 방식은 공식 문서에 설명한 방식과 조금 다를 수 있다.
공식 문서에서는 하나의 테스트 클래스 별로 컨테이너를 띄우도록 설명하고 있지만 실제 CI/CD 시 각 테스트마다 컨테이너를 올리고 종료하면 시간이 많이 소모된다. 사용한 컨테이너를 한 번만 띄우고 모든 테스트 종료 시 컨테이너를 종료할 수 있도록 구현한다.
static 설정을 통해 클래스가 메모리에 로드 될 때 컨테이너를 띄우고 실행시킨다. (한번만)
public class MemberServiceIntegrationTest extends TestContainerConfig{}
이처럼 테스트 컨테이너 클래스를 상속한 테스트 클래스를 테스트 시 컨테이너를 먼저 띄우고 테스트를 진행한다.
테스트 컨테이너가 무조건 좋은 것인가?
꼭 그렇지 않다. 테스트 시 컨테이너를 띄우고 종료하는 과정이 포함되기 때문에 그 만큼 테스트 시간이 오래 걸린다. 따라서, 꼭 필요한 상황에서 사용하는 것이 좋다.
참고자료
Testcontainers
Testcontainers is an opensource library for providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
testcontainers.com