Testcontainers는 Docker 컨테이너를 사용하여 테스트 환경을 동적으로 생성하고 관리할 수 있는 Java 라이브러리입니다. 이를 사용하면 데이터베이스, 메시지 큐, 웹 서버 등 다양한 서비스를 테스트에 쉽게 통합할 수 있습니다.
코드를 보시면 더욱 이해하기가 쉽습니다.
먼저, 프로젝트의 build.gradle 파일에 Testcontainers 의존성을 추가해야 합니다
testImplementation 'org.testcontainers:testcontainers:1.19.3'
testImplementation 'org.testcontainers:junit-jupiter:1.19.3'
이 의존성을 추가함으로써, Testcontainers 라이브러리를 테스트 코드에서 사용할 수 있게 됩니다.
Testcontainers를 사용한다면 원하는 컨테이너를 테스트를 실행하면서 실시간으로 띄웠다가 내릴수 있습니다.
여기서는 redis를 기준으로 작성해보겠습니다.
@Testcontainers public class RedisContainerTest { @Container private GenericContainer redisContainer = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine")) .withExposedPorts(6379); ... }
이 코드에서 @Container
어노테이션은 Testcontainers가 해당 필드에 Docker 컨테이너를 실행하도록 지시합니다.
@Container
어노테이션을 달아줌으로써 컨테이너의 시작과 종료를 저희가 직접 호출 하지 않고 테스트의 생명주기와 같이 돌 수 있도록 해줄 수 있습니다.(원래라면 start,stop등으로 종료를 해줘야 합니다.)
DockerImageName.parse("redis:5.0.3-alpine")
를 이용하여 어떤 도커 이미지를 띄울 것인지를 정의하고 있습니다. 그냥 string으로 넣어주셔도 됩니다.withExposedPorts(6379)
를 통해 내부의 6379랑 연결시켜주었습니다. 외부(호스트)의 포트는 랜덤으로 연결되고 이때 랜덤 포트를 내부 컨테이너의 6379와 연결시켜주는 작업입니다.GenericContainer
클래스는 다양한 설정 옵션을 제공합니다:
.withEnv("REDIS_PASSWORD", "yourpassword")
를 사용하여 컨테이너에 환경 변수를 설정할 수 있습니다..withCommand("redis-server", "--appendonly", "yes")
를 사용하여 컨테이너 시작 시 실행할 명령어를 지정할 수 있습니다..withFileSystemBind("/local/path", "/container/path")
를 사용하여 호스트와 컨테이너 간 파일 시스템을 마운트할 수 있습니다.@Testcontainers
public class MyTest {
@Container
private GenericContainer redisContainer = new GenericContainer(DockerImageName.parse("redis:5.0.3-alpine"))
.withExposedPorts(6379);
private RedisTemplate<String, Object> redisTemplate;
@BeforeEach
void setUp() {
// RedisTemplate 설정
String redisHost = redisContainer.getHost();
Integer redisPort = redisContainer.getFirstMappedPort();
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration(redisHost, redisPort);
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisConfig);
lettuceConnectionFactory.afterPropertiesSet();
redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
redisTemplate.afterPropertiesSet();
}
@Test
void test1() {
redisTemplate.opsForValue().set("yohan","hello");
String yohan = (String)redisTemplate.opsForValue().get("yohan");
Assertions.assertEquals(yohan,"hello");
}
}
위에서는 redisTemplate을 이용하였습니다.
@BeforeEach
를 보면redisContainer.getHost()
와redisContainer.getFirstMappedPort()
가 보이는데 해당 메소드들을 통해 연결된 host와 port를 가져올 수 있습니다.
이를 통해 testcontainer로 띄운 redis의 설정 값을 가져와 test에 연결할 수 있습니다.redis와 관련한 작업을
redisTemplate
을 이용하여 처리하였습니다.위의 방식외에도
RedisClient
와StatefulRedisConnection
을 이용하는 방식도 있습니다.
GenericContainer의 경우 범용적으로 사용하는 방식이라면 testconatiner가 전용으로 지원해주는 container들도 존재합니다.
아래는 mysql과 관련한 코드입니다.
@Testcontainers
public class MySQLContainerTest {
@Container
private MySQLContainer mysqlContainer = new MySQLContainer(DockerImageName.parse("mysql:8.0.26"))
.withDatabaseName("testdb")
.withUsername("user")
.withPassword("password");
@BeforeEach
void setUp() {
// MySQL 설정
String jdbcUrl = mysqlContainer.getJdbcUrl();
String username = mysqlContainer.getUsername();
String password = mysqlContainer.getPassword();
//연결 작업 수행
}
}
mysqlContainer
를 이용한다면 이름, 비밀번호 등을 더욱 쉽게 설정 할 수 있습니다.
Testcontainers를 사용하면 테스트 환경을 빠르고 쉽게 구성할 수 있으며, 이를 통해 테스트의 신뢰성과 일관성을 크게 향상시킬 수 있습니다.