testContainer도입하기 (feat. 중형(통합)테스트 작성)

첫 중형(통합) 테스트를 작성하면서 testContainer를 사용하기로 해보았다. 이미 앞선 선구자들에 의해 아주많은 글들이 있었다. 또한 매 테스트마다 container가 반복생성되어 테스트시 불필요한 시간이 낭비되게 되고, 나름 여러가지 방법들을 통해 단 하나의 생성된 컨테이너를 재활용해서 테스트 시간을 단축하는것. 여기까지가 정해진 레파토리로 파악된다.
(테스트컨테이너는 테스트 환경에서 실제와 유사한 외부 서비스(예: DB, Redis 등)를 도커 컨테이너로 실행해 신뢰성 높은 통합 테스트를 가능하게 해준다. 그래서 쓴다(또 무조건 도커를 쓰는건 아니다 일부환경과 서비스에 따라 도커를 쓰지 않고도 자체적으로 가능하다고는 한다))
우리는 db로 mysql과 redis, s3를 사용한다. 그래서 써보자.
(s3는 aws꺼라 못쓴다. 그래서 testContainer는 LocalStack이라고 쉽게말해 aws환경을 흉내내서 사용해볼 수 있게끔 기능을 제공해준다.)
우선 테스트 컨테이너를 사용하는 방법은 크게 3가지 정도로 나눠볼 수 있을것 같다.
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15.3")
.withDatabaseName("testdb")
.withUsername("testuser")
.withPassword("testpass");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
1. 다음과 같이 전통적인 방법으로는 수동으로 컨테이너를 만들고 컨테이너의 접속 정보를 @DynamicPropertySource로 등록해주는 방법이다.
2. 근데 스프링부트가 3.1버전으로 들어오면서 이제는 @ServiceConnection 라는 애노테이션으로 spring이 자동으로 연결정보를 인식해서 주입해주게끔 업그레이드해 주었다. 여기확인
절대다수의 블로그가 1번방법만 쓰고 있었다. 2번방법을 안쓰는 특별한 이유가 있는건지, 다른 어떤 이유때문에 1번으로 해야하는지 아직은 잘 모르겠다.
spring:
datasource:
url: jdbc:tc:mysql:8.0.37: ///testdb
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
3. 꿀팁인데 jdbc를 쓰는 경우 testContainer를 수동으로 생성하지 말고 그냥 설정파일에서(yml등) url을 간단하게 변경해주고 driver-class-name을 다음과 같이 명시해 주는것 만으로도 별다른 작업없이 사용할 수 있다고 한다. 여기확인
url에서 :tc: 를 붙여주면 된다고 한다.

그런데 레디스는 jdbc기반이 아니기 떄문에 저렇게 못쓴다. 따라서 별도로 testContainer를 만들어줘야 한다. 하지만 1번방법으로 datasource를 주입해주는 대신 2번 방법으로 사용해볼 수 있을것 같다.
그렇게 testContainer를 사용함으로써 테스트진행마다 새로운 mysql을 사용하게된다. 테스트 환경의 통일성을 가져올 순 있지만 비어있는 db가 된다. 그래서 알아봤더니 보편적으로 flyway를 사용해서 스키마를 만들어주는것 같다.
우리는 이미 flyway를 사용하고 있는 상태다. 하지만 v1부터 모든 테이블을 정의하면서 시작한게 아닌 기존 스키마가 갖춰진 상태에서 중간부터 도입을 한 상태다. 또한 과거 마이그레이션 데이터들을 모두 실행하는것또한 테스트코드 실행에 있어 속도감소의 영향이 있을것이라 생각했기에 우리는 최신 db를 간단하게 명령어로 dump로 가져와서 test전용 마이그레이션영역을 분리해준뒤, 해당 sql을 삽입해 사용하는 방식으로 하였다.

dump따는건 관리자권한으로 실행한 명령프롬프트에 아래처럼 입력했다.
mysqldump -u root -p --no-data --routines --triggers --compact --default-character-set=utf8 kustaurant_local | Out-File -FilePath V0__baseline.sql -Encoding utf8
--no-data 는 데이터를 제외해준다.
그렇게 sql을 가져오게 되지만, fk설정이 있는경우 순서보장이 되어있지 않다. 따라서 가져온 sql문 위아래 끝에 fk제약 감시를 잠시 꺼주는 설정이 필요하다 (위 명령어에서 설정을 추가해 보장한채로 가져올 수도 있다고 한다)
SET FOREIGN_KEY_CHECKS = 0;
SET FOREIGN_KEY_CHECKS = 1;
해당 라인을 맨 위와 맨 끝에 넣어주면 된다.
그리고 flyway table 생성문도 sql에 포함되있다. 근데 이 테이블은 flyway가 자동으로 만들어줘야 한다 따라서 해당 쿼리문도 찾아서 지워줘야 한다.
그리고 테스트를 돌려본다.

이렇게 testContainer의 성공적인 도입이 끝났다.
1) 테스트 컨테이너를 사용한 중형테스트를 github action 에서 테스트 자동화 시켜보자
2) 아직 테스트에서 레디스나 s3를 활용하지 않고있기에 추후 내용 추가할 예정
3) 테스트 컨테이너의 반복 빌드 ? 문제를 테스트해봤는데 별다른 설정을 하지않았는데도 하나만 잘 쓰는것 같아서 우선 해당이슈는 잠시 보류 ..
'개발[프로젝트] > 쿠스토랑' 카테고리의 다른 글
| post패키지 리팩토링하기 (2) | 2025.08.30 |
|---|---|
| 식당 티어산정과 조회수 정책 변경, 음식점 목록조회 캐싱 도입 (0) | 2025.07.31 |
| [쿠스토랑] 리팩토링(2) - 평가/평가 댓글 기능의 문제점과 개선안 (0) | 2025.06.28 |
| 대 쿠스토랑 모니터링 시대의 시작 (0) | 2025.06.18 |
| 웹 세션/앱 jwt - Naver/Apple 로그인 통합 리팩토링 (로그인2탄) (0) | 2025.06.13 |