Testcontainers는 도커를 이용하여 테스트 환경을 분리해주는 라이브러리이다.

테스트 수행 시 DB 등의 외부 환경은 운영 환경과 다르게 구축해야 할 필요가 있는데, 보통은 로컬 PC 에 테스트 전용 DB 를 만들어서 사용해왔다.

RDB 까지는 이렇게 독립적인 환경에서 테스트를 한다고 하더라도, Redis 나 Elasticsearch 와 같은 데이터저장소들은 개발에 참여하는 개개인이 모두 로컬 환경을 설정하는 것은 쉬운 일이 아니다.

이럴 때 도커는 매우 적절한 선택이 될 수 있고, Testcontainers 는 그 도커의 설정도 필요없게끔 Convention 이 설정되어 있기 때문에 사용하기에 매우 편리하다.


설치

junit 4 junit 5 ← 버전 별로 설치 방법이 다르다.

// kotlin 코드
testImplementation("org.testcontainers:testcontainers:${Versions.testcontainersVersion}")
testImplementation("org.testcontainers:junit-jupiter:${Versions.testcontainersVersion}")

공식 문서에 보면 다양한 의존성들을 설치하는데, 본인이 필요한 것을 골라서 설치하면 된다.


컨테이너 재사용 설정 방법

제대로 설치하고 실행해보면, 테스트 수행 시에 도커 컨테이너가 실행되는 것을 볼 수 있다.

그런데 테스트 수행 시 마다 새로운 컨테이너를 실행하니, 시간이 매우 오래 걸린다.

이를 피하기 위해 컨테이너를 재사용하고자 한다.

Testcontainers Github 재사용 기능 PR


Local 환경에 재사용 설정 추가

$ vim ~/.testcontainers.properties
 
testcontainers.reuse.enable=true        // 추가


컨테이너 Singleton 설정

문서에 보면 Shared container, Singleton Container 이렇게 2가지 방식이 소개되어 있는데, 여러 단위 테스트에 적용하기에는 Singleton 방식이 더 적합해 보인다.

@Testcontainers
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
abstract class AbstractContainerBaseTest {
 
    companion object {
        @JvmStatic
        protected val MY_SQL_CONTAINER: MySQLContainer<*> = MySQLContainerProvider()
            .newInstance()
            .withReuse(true) as MySQLContainer<*>
 
        @JvmStatic
        protected val ELASTICSEARCH_CONTAINER: ElasticsearchContainer = ElasticsearchContainer(
            "docker.elastic.co/elasticsearch/elasticsearch:7.12.1"
        ).withReuse(true)
    }
 
...


재사용 메소드 이용

.withReuse(true) 함수를 이용하여 해당 컨테이너를 재사용 하도록 지정해준다.


실행

테스트를 실행하기 전, 도커를 실행해야 한다.

테스트를 수행한다.

$ ./gradlew test 

컨테이너들이 자동으로 생성되었다.

본 환경에서는 재사용 설정을 해두었기 때문에 테스트가 종료된 이후에도 컨테이너가 실행되고 있다.

도커 컨테이너 stat 을 살펴보자

이렇게 자원을 계속 사용하고 있다.

따라서 테스트를 수행하고 난 이후에 더이상 사용할 필요가 없다면 해당 컨테이너를 종료시켜야 한다. (이 부분이 좀 찝찝한데, 더 좋은 방법이 있는지 좀 더 확인이 필요하다.)