테스트 코드 작성 시 동일한 개발 환경을 구축하기 위해서 Testcontainers 환경을 구축해봤다.
테스트 컨테이너는 JUnit을 지원하는 Java 라이브러리로, 도커 컨테이너 기반의 일회용 인스턴스를 제공한다. 각종 DBMS의 이미지를 이용해 내가 아는 DB 그대로 사용할 수 있고, 통합 테스트, UI 테스트 등 각종 테스트에 활용 가능하다.
스프링에서 기본적으로 지원해주는 H2 데이터베이스는 별도의 설정이 필요없고 인메모리 기반이라 빠르지만, 운영 환경의 데이터베이스와 일부 다르게 동작할 수 있다. Testcontainers는 실제 운영 환경과 유사한 데이터베이스 환경에서 테스트할 수 있어서 잠재적인 문제를 사전에 발견할 수 있다.
여기서는 MySQL을 기준으로 설정했다. 다른 DB를 사용한다면 공식 문서를 참고하자.
당연히 Docker는 기본적으로 설치되어 있어야 한다.
build.gradle
// test container
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:mysql:1.20.6' // MySQL 컨테이너 사용
AbstractIntegrationTest.java
@Testcontainers
public abstract class AbstractIntegrationTest {
@Container
protected static final MySQLContainer<?> MYSQL_CONTAINER = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("test-db")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void overrideProps(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", MYSQL_CONTAINER::getJdbcUrl);
registry.add("spring.datasource.username", MYSQL_CONTAINER::getUsername);
registry.add("spring.datasource.password", MYSQL_CONTAINER::getPassword);
registry.add("spring.datasource.driver-class-name", MYSQL_CONTAINER::getDriverClassName);
registry.add("spring.jpa.hibernate.ddl-auto", () -> "create");
}
}
UserRepositoryTest.java
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryTest extends AbstractIntegrationTest {
@Autowired private UserRepository userRepository;
@DisplayName("이메일로 유저 조회")
@Test
void givenEmail_whenFindByEmail_thenWorksFine() {
// given
User user = new User("test@email.com", "password", UserRole.USER);
userRepository.save(user);
String email = "test@email.com";
// when
Optional<User> result = userRepository.findByEmail(email);
// then
assertThat(result).isPresent();
assertThat(result.get().getUserRole()).isEqualTo(UserRole.USER);
}
}
UserServiceIntegrationTest.java
@SpringBootTest
class UserServiceIntegrationTest extends AbstractIntegrationTest {
@Autowired private UserService userService;
@Autowired private UserRepository userRepository;
@DisplayName("유저 조회")
@Test
void givenSavedUser_whenFindUserByEmail_thenReturnUserResponse() {
// given
String email = "test@email.com";
User user = new User(email, "password", UserRole.USER);
userRepository.save(user);
// when
UserResponse response = userService.getUser(1L);
// then
assertThat(response.getId()).isEqualTo(1L);
assertThat(response.getEmail()).isEqualTo("test@email.com");
}
}