-
Notifications
You must be signed in to change notification settings - Fork 2
TestContainers 도입기
TestContainers의 개념과 도입하게 된 배경을 정리합니다.
첫째로, 테스트 환경과 개발 환경의 일치를 위해서입니다.
우리 팀은 H2와 MySQL의 차이로 인해 테스트 코드가 동작하지 않는 문제를 겪었습니다.
이를 해결할 필요가 있습니다.
둘째로, Redis의 기능을 포함해서 테스트하기 위해서입니다.
서비스코드에 Redis의 락을 사용하는 부분이 있는데, 이를 테스트하기 위헤서는 테스트용 Redis가 필요합니다.
TestContainers를 사용함으로써 테스트 코드에서 간단하게 Redis를 사용할 수 있습니다.
셋째로, 개인의 환경으로 인해 테스트의 성공, 실패가 달라지는 상황을 막기 위해서입니다.
1,2 번째 목적 달성만을 위한다면, 로컬에서 도커를 띄우는 방식으로 해결할 수도 있습니다.
하지만 개발자마다 설정을 다르게 하면 테스트 코드가 통과하지 않을 수 있습니다.
실제로 제 로컬에서 테스트코드가 통과되는 것을 확인하고 merge 했음에도,
신규 개발자가 테스트코드가 돌아가지 않는다고 도움을 요청한적이 있었습니다..😭
넷째로, CI 도입을 위해서입니다.
문제가 없는 코드만이 default 브랜치에 머지되어야 합니다.
지금까지 우리 팀은 이를 '임베디드 H2 사용 & 로컬 MySQL,Redis 컨테이너'로 확인했습니다만,
앞서 언급한 문제들이 있었으므로 CI를 도입이 필요한 상황입니다.
CI에서는 로컬 컨테이너를 사용할 수 없으므로, TestContainers 도입이 반드시 필요합니다.
- TestContainers는 docker를 활용하여 테스트 환경을 제공합니다.
- TestContainers를 실행하려면, 테스트가 돌아가는 기기에 docker가 깔려있어야 합니다.
- 적용하는 방법으로는, 1)소스 코드를 통한 방법과 2)JDBC를 사용하는 경우, yml로 설정하는 방법이 있습니다.
@Testcontainers // ❗️ JUnit extension
public class MySQLTestContainer {
@Container // ❗️ 스캔 대상
private static final MySQLContainer<?> mysqlContainer;
@DynamicPropertySource // ❗️ 동적으로 값 설정
static void mysqlProperties(DynamicPropertyRegistry registry) {
if (mysqlContainer.isRunning()) {
registry.add("spring.datasource.url", mysqlContainer::getJdbcUrl);
}
}
static {
mysqlContainer = new MySQLContainer<>("mysql:8.0");
mysqlContainer.start();
}
}
-
@Testcontainers
어노테이션은 JUnit extension 입니다. - 이 extension은
@Container
어노테이션이 붙은 필드를 찾고, 각 컨테이너의 생명주기를 관리합니다. -
@Container
이 붙은 필드가- 인스턴스 필드이면, 컨테이너가 각 테스트마다 생성/삭제되지만,
- static 필드이면, 처음 시작할때 생성, 모든 함수가 종료될 때 삭제됩니다.
-
@DynamicPropertySource
어노테이션을 활용해서 config 를 동적으로 설정할 수 있습니다.
spring:
datasource:
url: jdbc:tc:mysql:8.0:///test // ❗️tc url 설정
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
username: test
password: test
- jdbc를 사용할 수 있는 데이터베이스의 경우, url 설정만으로 테스트 컨테이너를 사용할 수 있습니다.
- JDBC URL이
jdbc:tc:
로 시작하면, TestContainers의 특수 JDBC 드라이버가 활성화됩니다. - 이 드라이버는 설정 정보를 읽어 자동으로 컨테이너를 설정/생성합니다.
얼핏 보면 yml 방법이 더 간단해보입니다만...
이 방법은 'jdbc를 사용할 수 있는 데이터베이스'에 한정된 것이므로, 다른 테스트 컨테이너는 코드로 구현해야 합니다.
따라서 통일감을 위해서 jdbc url 만으로 설정할 수 있는 것들도 소스코드로 설정하는게 더 좋다고 생각합니다.🧐
소스코드 방식을 사용할 경우, 테스트 컨테이너가 클래스 단위로 적용됩니다.
따라서 다른 테스트 클래스에 반복적으로 적거나 상속을 하는 방법으로 재사용할 수 있습니다.
하지만 테스트 컨테이너를 사용하는 모든 곳에 저 코드를 적는 것은 너무 중복 코드가 많이 생길 것 같고,
상속을 하자니 '한번뿐인 상속의 기회'를 테스트 컨테이너에 사용하기도 아깝다는 생각이 들었습니다.
따라서 컨테이너를 Configuration으로 등록하고, 필요한 곳에서 사용할 수 있도록 커스텀 어노테이션을 만들어주도록 했습니다.
구현 방법은 이 PR을 참고하면 됩니다👍