반응형
Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 컴퓨터과학
- 인공지능
- 머신러닝
- 네트워크
- 데이터과학
- 빅데이터
- 소프트웨어공학
- 버전관리
- 프로그래밍
- 자바스크립트
- 데이터분석
- Yes
- 네트워크보안
- 소프트웨어
- 클라우드컴퓨팅
- 데이터베이스
- 컴퓨터공학
- 보안
- 디자인패턴
- springboot
- 컴퓨터비전
- 프로그래밍언어
- 사이버보안
- 데이터구조
- I'm Sorry
- 웹개발
- 알고리즘
- 자료구조
- 딥러닝
- 파이썬
Archives
- Today
- Total
스택큐힙리스트
멀티모듈 테스트 격리 & Fixture 전략 본문
반응형
왜 멀티모듈에서 테스트 격리가 더 어려울까?
모놀리식 프로젝트는 src/test 한 곳만 관리하면 되지만, 멀티모듈은 컨텍스트가 분리되어 있어
- 모듈 간 의존성 루프
- 무겁고 느린 공통 SpringBootTest
- 서로 다른 DB 스키마·데이터 충돌
같은 문제가 폭발적으로 늘어납니다. 오늘은 실제 현업에서 검증된 테스트 격리와 Fixture 공유 노하우를 정리합니다.
1️⃣ 테스트 유형별 분리 기준
- Unit Test : 모듈 내부 클래스만 테스트, JUnit5 + Mockito.
- Slice Test : @DataJpaTest, @WebMvcTest 등 스프링 슬라이스.
- Integration Test : 여러 모듈 협업 + 외부 시스템(Testcontainers).
- E2E Test : API → DB → 메시징 전 구간 검증(Cypress).
Rule of Thumb — “단일 모듈 책임은 Unit/Slice, 모듈 협업은 Integration”로 경계를 명확히!
2️⃣ Gradle testFixtures 플러그인으로 공통 Fixture 공유
- 모듈 설정
plugins { id("java-test-fixtures") } - 공유 코드 배치
src/testFixtures/java 에 DummyMember, SampleOrder 같은 더미 엔티티·빌더 클래스 저장. - 의존성 선언 — 다른 모듈에서
testImplementation(testFixtures(project(":core")))
- 장점
- 프로덕션 코드 오염 X
- 컴파일 타임 의존성만 추가 → 빌드 속도 유지
- 모듈별 서로 다른 Fixture 버전 관리 가능
3️⃣ Testcontainers로 모듈별 격리 DB 구동
@Testcontainers
class MemberRepositoryTest {
@Container
val maria = MariaDBContainer("mariadb:11").apply {
withDatabaseName("member_db")
}
}
- 모듈마다 고유 데이터베이스명 → 데이터 충돌 방지
- CI에서만 컨테이너 기동, 로컬은 H2 등 인메모리로 대체하는 profile 전략 추천
4️⃣ @DynamicPropertySource로 런타임 설정 주입
@DynamicPropertySource
fun dbProps(registry: DynamicPropertyRegistry) {
registry.add("spring.datasource.url") { maria.jdbcUrl }
}
- 모듈이 다르더라도 동일한 패턴으로 DB·Redis·Kafka URI를 주입
- 스프링 컨텍스트 재사용이 불가능한 경우에도, 매 테스트마다 정확한 환경 보장
5️⃣ Mock Server( WireMock )로 외부 API 고립
멀티모듈 프로젝트에서 api 모듈은 외부 결제·SMS 서버를 호출합니다.
- @AutoConfigureWireMock(port = 0)
- 고정 stub 파일을 src/test/resources/mappings 에 배치
- 테스트 완료 후 자동 종료 → 다른 모듈과 포트 충돌 없음
6️⃣ 테스트 네이밍 & 폴더 컨벤션
core
└─ src
└─ test
├─ unit
├─ slice
└─ integration
- 폴더 이름이 테스트 레벨을 드러내면 리뷰·코드 탐색 속도가 올라감
- Gradle --tests unit.* 식으로 레벨별 선택 실행 가능
7️⃣ CI에서 병렬 실행 + 캐시
- ./gradlew test --parallel --continue
- GitHub Actions strategy.matrix 로 모듈별 Job 분리 → 실패 모듈만 재시도
- org.gradle.caching=true 를 켜고, 필요 시 원격 캐시 서버 연결
8️⃣ 흔히 놓치는 Pitfall 3
- 테스트 전용 설정 클래스의 패키지가 public 모듈로 노출돼 의존성 루프 발행
- Fixture에 @Component 등록 → 프로덕션 빈 스캔에 끼어들어 런타임 오류
- 공통 Embedded Redis 포트 중복 → 각 모듈마다 @DynamicPropertySource로 난수 포트 지정
✨ 정리
멀티모듈 환경에선 “작게 쪼개고, 확실히 격리”가 생존 전략입니다.
- testFixtures로 중복 코드 제로
- Testcontainers & WireMock으로 외부 의존성 차단
- 폴더·CI 분리로 빌드 시간 단축
이제 테스트가 빌드의 병목이 아닌, 품질 속도를 높이는 엔진이 될 것입니다. 다음 글에서는 GitHub Actions + Testcontainers 캐시 최적화를 다룰 예정이니 기대하세요!
반응형
'개발' 카테고리의 다른 글
모놀리스→멀티모듈→마이크로서비스 전환 로드맵 (1) | 2025.07.12 |
---|---|
멀티모듈 핵심 개념 이해하기 (0) | 2025.07.12 |
자바 스프링 개발 시작하기 - 6일차 빌드 & 의존성 마스터하기 (1) | 2025.07.12 |
Index Skip Scan 완전 정복: 선두 칼럼이 없어도 인덱스를 타는 마법 (2) | 2025.07.11 |
Index Skip Scan과 Covering Index를 활용한 초고속 페이징 쿼리 패턴 (0) | 2025.07.11 |
Comments