테스트 200개에 @SpringBootTest를 붙였다가 CI가 20분이 된 이유
문제 발생
테스트를 늘릴수록 CI가 느려졌습니다. 컨트롤러 매핑 하나를 확인하는 테스트도 DB와 메시지 브로커까지 올리고 있었습니다.
@SpringBootTest
class PostControllerTest { ... }게다가 클래스마다 @MockBean이나 프로퍼티가 조금씩 달라서, 컨텍스트가 계속 새로 만들어졌습니다.
원인 분석
@SpringBootTest는 전체를 띄웁니다. Spring Boot 문서 설명대로 이 애노테이션은 SpringApplication을 통해 전체 애플리케이션 컨텍스트를 로드합니다. 컨트롤러 하나를 보려는 테스트에는 과합니다.
문서는 이 상황을 위해 슬라이스를 제공합니다 — 예를 들어 @WebMvcTest는 스캔 범위를 @Controller, @ControllerAdvice, Converter, Filter 등으로 제한하고 일반 @Component와 @ConfigurationProperties 빈은 제외하며 MockMvc를 자동 구성합니다. 문서가 드는 동기도 정확히 우리 상황입니다 — Spring MVC 컨트롤러가 URL을 올바르게 매핑하는지 테스트하고 싶지만 그 테스트에 데이터베이스 호출을 끌어들이고 싶지는 않은 경우.
느려진 두 번째 이유는 캐싱입니다. 문서 설명대로 Spring의 테스트 프레임워크는 테스트 사이에 애플리케이션 컨텍스트를 캐시하므로, 테스트들이 같은 설정을 공유하는 한 컨텍스트 로딩은 한 번만 일어납니다. 뒤집으면 설정이 조금이라도 다르면 컨텍스트가 새로 만들어집니다 — @MockBean 조합이 다르면 그것도 다른 설정입니다.
해결 방안
- 계층에 맞는 슬라이스를 씁니다.
@WebMvcTest(PostController.class) // 웹 계층만
@DataJpaTest // JPA 계층만
@JsonTest // 직렬화만-
설정 변형을 줄입니다. 공통 목 구성을 부모 클래스나
@TestConfiguration으로 모아 컨텍스트 종류를 손에 꼽을 수 있게 만듭니다. 캐시 적중률이 곧 CI 시간입니다. -
슬라이스를 겹쳐 쓰지 않습니다. 문서가 명시합니다 — 여러
@…Test애노테이션을 한 테스트에 함께 쓰는 것은 지원되지 않습니다. 필요하면@SpringBootTest에 개별@AutoConfigure…를 조합합니다. -
webEnvironment를 의식해서 고릅니다. 기본값MOCK은 서버를 띄우지 않습니다.RANDOM_PORT는 실제 서버가 필요할 때만 씁니다 — 비용이 다릅니다. -
통합 테스트는 소수만 남깁니다. 전체 컨텍스트가 필요한 시나리오(인증 흐름, 트랜잭션 경계)는 분명히 있습니다. 그것만
@SpringBootTest로 두고 나머지는 슬라이스나 순수 단위 테스트로 내립니다. -
컨텍스트가 몇 번 만들어지는지 확인합니다. 로그의 컨텍스트 시작 횟수를 세보면 캐시가 실제로 듣고 있는지 바로 드러납니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.