Files
llm-wiki/raw/blog-topics/test-taxonomy-archunit-enforcement-2026-06-19.md
T

94 lines
5.4 KiB
Markdown

---
title: blog-topic / test-taxonomy-archunit-enforcement-2026-06-19
source_type: blog-topic
status: raw
related_branches: [feature-test-taxonomy-fixture-contract]
related_projects: [ca-tmpl]
tags: [blog-topic, ca-tmpl, archunit, test-taxonomy, testcontainers, spring-test-slice, fixture]
created: 2026-06-19
status_label: ready-for-canonical
target_audience: backend-engineer
inspiration_url:
archive_url:
---
# blog-topic: test-taxonomy-archunit-enforcement-2026-06-19
> Layer: `raw/blog-topics/` — 채용공고가 아닌 작업·학습·트러블슈팅에서 나온 블로그 글감 원석. canonical 정제 전 raw 후보이며, `wiki/blog/` 직접 생성 근거가 아니다.
## Parent / 부모
- [[raw/branch-notes/feature-test-taxonomy-fixture-contract]] — 6-level test taxonomy 계약을 _문서_ 에서 _빌드가 강제하는 규칙_ 으로 옮긴 구현(2026-06-19).
## 트리거 / Trigger
- 트리거 유형: `branch-work`
- 트리거 날짜: 2026-06-19
- 트리거 연결 노트: [[raw/branch-notes/feature-test-taxonomy-fixture-contract]] — §테스트 계약 #4 와 D6/D7 drift 를 ArchUnit 규칙으로 닫은 작업.
## 글감 / Topic seed
테스트 분류(unit/contract/architecture/slice/integration/smoke)를 README 에 적어두는 것과, _잘못된 레벨에 놓인 테스트를 빌드가 거부_ 하게 만드는 것은 다르다. 후자를 ArchUnit 으로 구현한 사례.
핵심 3개 규칙:
1. **레벨 경계 = 의존 경계로 강제**: "contract·architecture 레벨 테스트는 Testcontainers 에 의존하면 실패." Testcontainers 를 쓰던 `bootstrap/contract/` 테스트 5개는 사실 integration 테스트가 contract 디렉터리에 mis-file 된 것 → `bootstrap/integration/` 으로 재분류한 뒤, `..contract..`/`..architecture..` 패키지가 `org.testcontainers..` 에 의존하면 fail 하는 규칙을 추가. 이렇게 하면 "5분 fast-feedback 게이트(unit+contract+architecture)" 가 컨테이너 기동 비용에 오염되는 것을 빌드가 막는다.
2. **Spring slice annotation 혼용 금지**: Spring 공식이 `@WebMvcTest` + `@DataJpaTest` 혼용을 "not supported" 로 명시(SB-SLICE-C2) → 한 클래스에 두 slice annotation 이 붙으면 fail.
3. **fixture 가 production classpath 로 새지 않게**: `..fixtures..` 패키지에 대한 production 코드 의존을 차단.
## 왜 흥미로운가 / Why it's worth writing
- "테스트 분류는 컨벤션" 이라는 통념을 깨는 구체적 메커니즘. `@Tag` 보다 강하게, _import graph_ 자체로 레벨을 강제한다.
- ArchUnit 함정 2개를 실제로 다룬다:
- `@AnalyzeClasses(DoNotIncludeTests)` 는 test 클래스를 못 본다 → 규칙 대상이 test 자체일 땐 manual `ClassFileImporter` 가 필요. ([[raw/interviews/archunit-manual-importer-vs-analyzeclasses]])
- `allowEmptyShould(true)` + positive control: 규칙이 진짜로 발화하는지 증명하지 않으면 vacuous pass. 본 작업은 Testcontainers 를 실제로 쓰는 integration 패키지에 규칙을 평가해 `hasViolation()==true` 로 non-vacuity 를 못박았다. ([[raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28]])
## 곁가지 / Tangents
- DIR_LEVEL drift("integration test 가 contract 폴더에 있다")처럼, 디렉터리 이름과 테스트 _레벨_ 이 어긋나면 fast-feedback 게이트 설계가 조용히 무너진다는 운영 교훈.
- 이 글감은 cross-branch [[raw/branch-notes/feature-ci-quality-gates-contract]](5분 budget 게이트의 CI 구현 owner)와 묶어 "테스트 피라미드를 CI 가 강제하는 법" 으로 확장 가능.
## 핵심 주장 후보 / Claim candidates
- 사실 후보:
- test taxonomy는 package/import graph로도 강제할 수 있다.
- contract/architecture level에서 Testcontainers dependency를 금지하면 fast-feedback gate 오염을 줄일 수 있다.
- 의견/해석 후보:
- test level은 이름표가 아니라 실행 비용과 dependency boundary의 계약이다.
## Outline seed
1. README taxonomy와 build-enforced taxonomy의 차이를 설명한다.
2. Testcontainers dependency, slice annotation, fixtures leak rule을 나눠 설명한다.
3. manual `ClassFileImporter`와 non-vacuity positive control의 필요성을 정리한다.
## Canonical 전환 후보 / Canonical extraction candidates
- `wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard.md` 후보:
- test taxonomy ArchUnit enforcement 글감.
- 필요한 추가 검증:
- 현재 test taxonomy rule과 relocated integration test evidence.
## Sources / 근거 후보
- [[raw/branch-notes/feature-test-taxonomy-fixture-contract]]
- [[raw/interviews/archunit-manual-importer-vs-analyzeclasses]]
- [[raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28]]
## 미해결 / Unknown
- 아직 확인해야 할 사실: CI 5min budget과 ArchUnit rule이 실제로 연결되어 release-blocking인지.
- 과장하면 안 되는 부분: 테스트 품질 전체를 보장한다고 쓰지 않고 level misplacement 방지로 제한한다.
## Decision / 처리 결정
- 액션: `promote-to-canonical`
- 이유: `wiki/projects/ca-tmpl/skeleton-governance-registry-verification-test-scorecard.md` 에 test taxonomy ArchUnit enforcement 글감으로 반영한다.
- 다음 단계: blogify 전 hosted CI와 local architecture test evidence를 분리한다.
## Related / 관련
- 관련 branch: [[raw/branch-notes/feature-test-taxonomy-fixture-contract]]