[TMT-295] test: persistence 통합 테스트 환경 — Testcontainers PostGIS - #70
[TMT-295] test: persistence 통합 테스트 환경 — Testcontainers PostGIS#70mingdodev wants to merge 4 commits into
Conversation
wnsvy607
left a comment
There was a problem hiding this comment.
컨테이너 수명(모듈당 싱글턴 1회 기동)·롤백 끈 이유·Flyway 적재·이미지 버전(imresamu/postgis:16-3.4, 로컬 compose와 일치) 고정까지 설계 판단이 전부 옳고 근거가 주석에 잘 남았습니다. 다만 한 줄짜리 [must]가 하나 있습니다.
[must] support/PersistenceTestConfiguration.kt — @SpringBootConfiguration이 support 패키지에 있는데, @DataJpaTest는 이 클래스를 테스트 클래스의 패키지에서 상위 방향으로만 탐색합니다(형제 패키지는 안 봄). 지금 스모크 테스트는 같은 패키지라 돌지만, 이 PR의 존재 이유인 TMT-208·227 어댑터 테스트를 관례대로 ...postgres.adapter에 만들면 Unable to find a @SpringBootConfiguration으로 기동 자체가 안 됩니다 — "PersistenceTest를 상속만 하면 된다"는 이 PR의 계약이 support 밖에서 깨져요. 수정은 한 줄: 설정 클래스를 모듈 루트 패키지(com.tmt.output.persistence.postgres)로 옮기거나, PersistenceTest에 @ContextConfiguration(classes = [PersistenceTestConfiguration::class])를 붙이면 됩니다.
[want] PersistenceTest.kt — persistence 모듈엔 test용 yml이 없어 슬라이스가 ddl-auto 기본값(none)으로 돕니다. 운영·로컬은 validate로 엔티티↔마이그레이션 드리프트에서 기동이 막히는데 정작 이 테스트는 그걸 못 잡아요. @DataJpaTest(properties = ["spring.jpa.hibernate.ddl-auto=validate"]) 한 줄이면 "마이그레이션이 검증 대상"이라는 이 PR의 의도가 엔티티 매핑까지 확장됩니다.
|
둘 다 반영했습니다.
|
wnsvy607
left a comment
There was a problem hiding this comment.
두 건 다 확인했습니다. 설정 클래스가 모듈 루트로 갔고, 무엇보다 adapter/AdapterSliceContextTest로 "형제 패키지에서도 뜬다"는 계약을 테스트가 지키게 한 것이 좋습니다 — 다음에 누가 support로 되돌리면 설명 없이 바로 걸립니다. ddl-auto=validate 고정도 들어가서 이제 엔티티↔마이그레이션 드리프트를 CI가 잡습니다. approve합니다.
Related Issue
Why
테스트 48개 중 실제 SQL이 도는 것이 하나도 없습니다. MockMvc
standaloneSetup(17개)과 Fake 포트(12개)뿐이고tmt-output-persistence에는 테스트 디렉터리 자체가 없었습니다.두 가지는 Fake로 원리적으로 검증이 안 됩니다.
UPDATE의 경합은 실제 트랜잭션·커밋 없이 재현되지 않는다. 조회 후 갱신하면 한 장이 두 번 쓰이는데 그 버그가 Fake에서는 드러나지 않는다EXPLAIN과 인덱스 선택은 실제 플래너가 필요하다. GiST를 타는지, 141k 실데이터에서 seq scan으로 떨어지는 조건이 있는지는 PostGIS 위에서만 알 수 있다전 어댑터에 붙이지 않고 이 둘로 한정했습니다. 나머지는 대부분 단순 CRUD라 Fake로도 잡히고, 9/12까지 일정에 맞지 않습니다.
그리고 main 자동 배포를 끄면서(TMT-290) DB 경로가 도는 환경이 하나도 없어졌습니다. 이대로면 릴리즈 태그를 끊는 순간이 실 DB 경로의 첫 실행이자 운영 배포가 됩니다.
What
persistence 어댑터를 실 PostGIS 위에서 테스트할 수 있게 됩니다. 컨테이너·Flyway·슬라이스 설정이 갖춰졌고, 각 구현 티켓은
PersistenceTest를 상속해 테스트만 쓰면 됩니다.스모크 4개로 바닥이 서 있는지 확인합니다 — PostGIS 확장 존재, Flyway 전량 적용,
place.locationSRID 4326, 롤백이 꺼져 커밋이 남는 것.테스트 자체는 각 구현 티켓(TMT-208·227)에서 씁니다. 이 PR은 바닥만 깝니다.
How
컨테이너는 모듈 전체가 하나를 공유합니다. 테스트 클래스마다
@Container를 붙이면 클래스 수만큼 기동돼 CI 시간이 배로 늡니다. 이 형태여야 나중에 테스트를 늘려도 기동 비용이 다시 들지 않습니다.트랜잭션 롤백을 끕니다 (
Propagation.NOT_SUPPORTED). 롤백을 두면 커밋이 없어 동시성 경합을 재현할 수 없습니다. 대신 테스트 간 데이터를 지우지 않고, 각 테스트가 자기 데이터를 만들어 그 id로만 단언하는 규칙으로 격리합니다. TRUNCATE보다 강한 조건이고, 덕분에 컨테이너 재사용도 안전합니다.스키마는 Flyway가 올립니다 — 마이그레이션 자체가 검증 대상이 됩니다.
이미지는
imresamu/postgis:16-3.4로docker-compose.local.yml과 맞췄습니다. 버전이 갈리면 실행 계획이 달라집니다.Notes for Reviewer
리뷰어가 로컬에서 돌리려면 Docker가 떠 있어야 합니다.
~/.testcontainers.properties에testcontainers.reuse.enable=true를 넣으면 컨테이너를 재사용해 반복 실행이 빨라집니다(선택). README에 한 줄 넣었습니다.CI 시간을 봐주세요. 도입 전 1분 39초
2분 10초 → 도입 후 3분 11초로 1분1분 30초 늘었습니다. 컨테이너를 모듈당 하나만 띄우므로 테스트를 늘려도 이 비용은 다시 들지 않지만, 2분 이상 더 늘어나면integrationTest태스크 분리를 다시 이야기하는 게 좋겠습니다.범위 밖으로 남긴 것 —
QuerydslConfig가JPAQueryFactory빈을 등록하는데 레포에서 쓰는 코드가 한 곳도 없습니다(어댑터 14개가 전부 Spring Data, 공간 쿼리는 네이티브@Query). 그래서 이 슬라이스에 넣지 않았습니다. 죽은 코드 정리는 별건이라 티켓을 따로 낼지 판단이 필요합니다.의존성은
test-containers번들로 묶어 persistence 모듈에만 넣었습니다. 공통 test 번들에 넣으면 전 모듈이 컨테이너 의존성을 끌어옵니다.Prompt Log
컨테이너 수명·격리 방식·이미지·스키마 적재·슬라이스 범위를 하나씩 정하고 시작했습니다.
격리는 처음에 매 테스트 TRUNCATE를 제안했는데, 근거가 "
@Transactional롤백이 동시성 테스트와 안 맞는다"였고 그건 "테스트마다 고유 데이터" 방식에는 해당되지 않았습니다. 후자가 더 강한 원칙이라 그쪽으로 정하고 TRUNCATE는 뺐습니다.슬라이스에 QueryDSL을 넣을지 물었다가, 실제로 쓰는 코드가 있는지 먼저 확인해서 없다는 것을 보고 제외했습니다.
Boot 4의 test 모듈 분리·
JdbcTemplate빈 미등록·PostGIS 이미지 호환 세 곳에서 막혔고, 다음에 같은 곳을 밟지 않도록 코드 주석으로 남겼습니다.