Testcontainers란?

Testcontainers란?

통합 테스트를 진행할 때 테스트 코드는 실제 DB 컨테이너에 연결하여 DB와의 상호작용을 검증한다. 만약 Docker Compose로 테스트 DB를 띄우는 경우 불편한 점은 다음과 같다.

  1. 이전 컨테이너 볼륨을 정리하지 않은 경우 이전 테스트 데이터가 남아 있을 수 있다.
  2. 테스트 실행 전 DB를 미리 구축해야 한다.
  3. 테스트 클래스마다 독립적인 DB 환경이 필요한 경우 컨테이너 생성, 연결 정보 설정, 종료 과정 등을 별도로 구현해야 한다.

통합 테스트를 더 편리하게 구성하고 관리하기 위해 Testcontainers를 사용한다. Testcontainers는 테스트를 실행할 때 Docker 컨테이너를 자동으로 생성하고 관리하는 테스트 라이브러리이다.

Testcontainers의 가장 큰 장점은 DB 컨테이너의 생명주기를 테스트 코드에서 선언적으로 관리할 수 있다는 것이다. 테스트 코드에서 필요한 DB 컨테이너를 정의하면 테스트 실행 시 자동으로 컨테이너를 생성하고, 테스트가 끝나면 종료하도록 관리할 수 있다. 즉, 개발자가 테스트 실행 전에 MySQL 컨테이너를 별도로 실행하거나 테스트 종료 후 직접 정리할 필요가 없다.

주요 어노테이션

Testcontainers 라이브러리가 제공하는 주요 어노테이션은 다음과 같다.

@Testcontainers

@Testcontainers
class UserRepositoryTest {
}

@Testcontainers 는 JUnit 5에서 Testcontainers가 제공하는 확장 기능을 활성화하는 어노테이션이다. JUnit에 TestcontainersExtension을 등록한다.

그렇다면 TestcontainersExtension 클래스는 무엇일까? JUnit의 테스트 실행 시점에 맞춰 컨테이너를 시작하고 종료하는 역할을 한다.


JUnit이 테스트 클래스를 실행하던 중 @Testcontainers 를 발견하면, TestcontainersExtension이 @Container 필드를 탐색한다. 이후 테스트 메서드 실행 전에 컨테이너를 시작하고, 테스트 메서드를 실행하고, 컨테이너를 종료한다.

@Container

그렇다면 @Container는 뭘까? JUnit의 Testcontainers 확장 기능이 관리할 컨테이너를 지정하는 어노테이션이다.

@Testcontainers
class UserRepositoryTest {

    @Container
    static MySQLContainer<?> mysql =
            new MySQLContainer<>("mysql:8.0");
}

여기서 MySQLContainer<?>은 MySQL 컨테이너를 표현하는 자바 클래스이다.

특정 테스트 클래스의 모든 테스트 메서드가 컨테이너 객체를 공유하도록 하려면 static 을 붙이면 된다. 만약 단순 인스턴스 필드로 선언하면 테스트 메서드 전후로 컨테이너가 시작 및 종료되며, 오버헤드가 커지게 된다.

@Container 가 Docker 컨테이너를 생성하는 것이 아니라, 해당 객체의 생명주기를 JUnit이 관리하도록 지정하는 것이다.

만약 TestcontainersExtension이 @Container가 붙은 필드를 발견하면, 테스트 수행 전후로 Docker 컨테이너를 실행 및 종료하는 start(), stop()에 해당하는 작업을 수행한다.

@ServiceConnection

Testcontainers가 실행한 컨테이너의 연결 정보를 Spring Boot에 자동으로 등록하는 어노테이션이다. Testcontainers가 아니라 Spring Boot에서 지원하는 어노테이션이다.

일반적으로 Spring Boot가 DB에 연결하려면 application.yml에 url, username, password 등이 있어야 한다. Spring Boot는 이 정보를 통해 DataSource를 구성하고 DB에 연결한다.

@SpringBootTest
@Testcontainers
class UserRepositoryTest {

    @Container
    @ServiceConnection
    static MySQLContainer<?> mysql =
            new MySQLContainer<>("mysql:8.0");

    @Autowired
    UserRepository userRepository;
}

@ServiceConnection을 사용하는 경우 yml에 DB 정보를 작성하지 않아도 된다. @Container에 의해 DB 컨테이너가 실행되면, JDBC URL, username, password 등을 확인할 수 있다. @ServiceConnection을 인식한 Spring Boot가 해당 정보를 통해 DataSource를 구성한다.