Jupiter / JUnit 5 확장으로 컨테이너 라이프사이클 관리하기
Jupiter / JUnit 5 확장으로 컨테이너 라이프사이클 관리하기
테스트 클래스마다 컨테이너를 직접 띄우고 내리는 코드를 반복하다 보면 테스트 프레임워크와 자연스럽게 통합되고 싶어져요. Testcontainers의 JUnit Jupiter 확장을 쓰면 @Testcontainers와 @Container 애노테이션 하나로 컨테이너의 시작·공유·정리를 프레임워크에 맡길 수 있어요. 이 페이지에서는 컨테이너를 테스트 메서드마다 다시 시작하거나 클래스 안에서 공유하는 두 가지 모드를 살펴볼게요.
본문
이 모듈은 JUnit Jupiter 확장 모델을 기반으로 한 API를 제공해요.
이 확장은 두 가지 모드를 지원해요.
- 테스트 메서드마다 다시 시작되는 컨테이너
- 테스트 클래스의 모든 메서드가 공유하는 컨테이너
Jupiter/JUnit 5 통합은 별도의 라이브러리 JAR로 패키징되어 있어요. 자세한 내용은 아래를 참고하세요.
확장
Jupiter 통합은 @Testcontainers 애노테이션으로 제공돼요.
이 확장은 @Container로 애노테이션된 모든 필드를 찾아서 그 컨테이너의 라이프사이클 메서드(Startable 인터페이스의 메서드)를 호출해요. static 필드로 선언된 컨테이너는 테스트 메서드 사이에서 공유돼요. 이 컨테이너는 어떤 테스트 메서드가 실행되기 전에 딱 한 번 시작되고, 마지막 테스트 메서드가 실행된 뒤에 중지돼요. 인스턴스 필드로 선언된 컨테이너는 테스트 메서드마다 시작되고 중지돼요.
참고: 이 확장은 순차 테스트 실행에서만 테스트되었어요. 병렬 테스트 실행에서 쓰는 것은 지원되지 않으며 의도하지 않은 부작용이 있을 수 있어요.
예시:
@Testcontainers
class MixedLifecycleTests {
// will be shared between test methods
@Container
private static final MySQLContainer MY_SQL_CONTAINER = new MySQLContainer("mysql:8.0.36");
// will be started before and stopped after each test method
@Container
private PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer("postgres:9.6.12")
.withDatabaseName("foo")
.withUsername("foo")
.withPassword("secret");
@Test
void test() {
assertThat(MY_SQL_CONTAINER.isRunning()).isTrue();
assertThat(postgresqlContainer.isRunning()).isTrue();
}
}
예시
Testcontainers 확장을 쓰려면 테스트 클래스에 @Testcontainers를 붙이면 돼요.
다시 시작되는 컨테이너
다시 시작되는 컨테이너를 정의하려면 테스트 클래스 안에 인스턴스 필드를 선언하고 @Container로 애노테이션하면 돼요.
@Testcontainers
class TestcontainersNestedRestartedContainerTests {
@Container
private final GenericContainer<?> topLevelContainer = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE)
.withExposedPorts(80);
...
@Test
void top_level_container_should_be_running() {
assertThat(topLevelContainer.isRunning()).isTrue();
...
}
@Nested
class NestedTestCase {
@Container
private final GenericContainer<?> nestedContainer = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE)
.withExposedPorts(80);
@Test
void both_containers_should_be_running() {
// top level container is restarted for nested methods
assertThat(topLevelContainer.isRunning()).isTrue();
// nested containers are only available inside their nested class
assertThat(nestedContainer.isRunning()).isTrue();
...
}
}
}
공유 컨테이너는 최상위 테스트 클래스의 static 필드로 정의하고 @Container로 애노테이션해야 해요. 공유 컨테이너는 중첩 테스트 클래스 안에서는 선언할 수 없다는 점을 기억하세요. 중첩 테스트 클래스는 non-static으로 정의돼야 하므로 static 필드를 가질 수 없기 때문이에요.
싱글톤 컨테이너
싱글톤 컨테이너 패턴도 JUnit 5를 쓸 때 하나의 선택지라는 점을 알아 두세요.
제한 사항
이 확장은 순차 테스트 실행에서만 테스트되었어요. 병렬 테스트 실행에서 쓰는 것은 지원되지 않으며 의도하지 않은 부작용이 있을 수 있어요.
프로젝트 의존성에 JUnit 5 지원 추가하기
pom.xml/build.gradle 파일에 다음 의존성을 추가하면 돼요.
testImplementation "org.testcontainers:testcontainers-junit-jupiter:2.0.5"
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<version>2.0.5</version>
<scope>test</scope>
</dependency>
더 알아보기
- 컨테이너 기반 테스트 시작하기 — GenericContainer의 기본 사용법
- 컨테이너 라이프사이클 수동 제어 — 프레임워크 없이 start()/stop() 직접 제어
- JDBC 지원 — JDBC URL로 임시 DB 사용하기