![[코드가 환경을 모르는 구조 6/7] 컨테이너는 왜 폭발하는가](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fv31psllp%2Fproduction%2F84f3d9c344480bec28c26726a1ef04c0407b32cd-1684x1030.png%3Fauto%3Dformat%26fit%3Dmax%26w%3D1200&w=3840&q=75)
Testcontainers 폭발을 막는 Gradle BuildService 기반의 스마트한 컨테이너 공유 전략
통합 테스트는 신뢰도가 높지만 느리다는 단점이 있습니다. 특히 Testcontainers를 쓸 때 컨테이너가 무한 증식하는 'dirty context' 문제를 해결하지 못하면 CI는 금방 마비됩니다. 본 아티클은 플렉스(flex) 팀이 Gradle BuildService를 이용해 단 하나의 컨테이너로 수많은 모듈의 통합 테스트를 격리하고 가속화한 실전 노하우를 담고 있습니다.
멀티모듈 프로젝트에서 통합 테스트 속도 저하로 고통받는 백엔드 엔지니어들에게 적극 추천합니다. 특히 Spring Boot 환경에서 Testcontainers 도입을 고민 중이라면 성능 최적화를 위한 필수 설계 지침서가 될 것입니다.
통합 테스트 시 Testcontainers를 사용할 때, Spring의 dirty context 현상으로 인해 불필요한 컨테이너가 중복 생성되어 CI 서버의 메모리 부하와 테스트 시간 지연이 발생한다. 특히 멀티모듈 프로젝트에서 모듈별로 서로 다른 컨텍스트 키가 생성되거나 @MockBean 사용 시 컨테이너가 무분별하게 복제되어 전체 빌드 속도가 급격히 저하되는 문제가 있다.
Gradle 8에서 제공하는 BuildService를 활용하여 빌드 전체 범위에서 단 하나의 컨테이너만 유지하는 '빌드 수준 싱글턴' 구조를 도입했다. 하나의 공유 컨테이너 내에서 각 모듈의 경로를 기반으로 논리적인 데이터베이스 스키마를 분리하고, Liquibase를 통해 모듈별 독립적인 테스트 환경을 구축하여 컨테이너 복제 문제를 해결했다.
실제 인프라를 사용하는 통합 테스트의 신뢰성을 그대로 유지하면서도, 컨테이너 기동 시간을 획기적으로 줄여 10분 이상 소요되던 CI 시간을 2분대로 단축했다. 이를 통해 개발자들이 테스트를 건너뛰지 않고 자주 실행할 수 있는 환경을 조성하여 '테스트 부식'을 방지하고 코드 품질을 안정적으로 관리할 수 있게 되었다.
Trade-off
BuildService는 단일 빌드 내에서는 싱글턴을 보장하지만, 로컬 환경에서 여러 빌드가 동시에 실행되는 경우 여전히 여러 개의 컨테이너가 뜰 수 있다. 또한 CI 환경에서는 매 실행마다 새로운 JVM이 시작되므로 빌드 간 컨테이너 재사용 이득이 제한적이며, 이를 보완하기 위해 별도의 스냅샷 캐시 전략이 추가로 필요하다.
Spring 테스트 프레임워크에서 특정 설정 변경으로 인해 기존 캐시된 ApplicationContext를 사용하지 못하고 새로 생성해야 하는 상태를 의미한다.
Gradle 빌드 실행 기간 동안 단일 인스턴스로 유지되며 Task 간에 상태를 안전하게 공유할 수 있는 서비스이다.
물리적인 데이터베이스 서버는 공유하되, 논리적인 데이터베이스(스키마)를 별도로 생성하여 데이터를 격리하는 방식이다.








