dev-testing
Source: skills/dev-testing/SKILL.md
Testing and QA router: strategy, harness choice, CI gates, TDD, and coverage.
테스트 없는 코드는 '동작하는 것 같다'에 머물고, 리팩토링이나 기능 추가 때 회귀를 잡지 못한다. AI 에이전트는 특히 얕은 해피패스 테스트만 작성하거나 실제 동작을 검증하지 않는 가짜 테스트를 만드는 경향이 있다. 이 스킬은 테스트 피라미드, 하니스 선택, CI 게이트, 커버리지 기준을 체계적으로 제공하여 변경의 위험도에 비례하는 검증을 보장한다.
LLM이 만드는 테스트의 가장 흔한 문제는 '동어 반복 테스트(tautology test)'다. expect(true).toBe(true)처럼 항상 통과하는 테스트, 또는 모든 의존성을 mock해서 실제 동작이 아니라 mock의 동작을 검증하는 테스트. LLM은 '테스트가 통과했다'는 신호를 만들도록 학습되었기 때문에, 테스트의 '질'보다 '존재'를 우선시한다.
또한 LLM은 해피 패스만 테스트한다. null 입력, 빈 배열, 경계값, 동시 접근, 네트워크 실패 같은 에지 케이스를 자발적으로 테스트하지 않는다. 이건 학습 데이터에서 해피 패스 테스트가 에지 케이스 테스트보다 압도적으로 많기 때문이다.
이 스킬이 해결하는 실제 문제
에이전트는 '테스트를 작성했습니다'라고 보고하지만, 실제로는 항상 통과하는 tautology 테스트(expect(true).toBe(true))이거나, 실제 동작을 검증하지 않는 mock만 잔뜩 있는 테스트를 만든다. 이 스킬은 테스트가 실제로 검증하는 것이 무엇인지 명시하게 한다.
에이전트가 프로젝트에 이미 Jest가 설정되어 있는데 Vitest를 새로 설치하거나, Playwright가 있는데 Cypress를 추가한다. Harness Selection은 기존 프로젝트의 테스트 인프라를 먼저 감지하고 활용하게 한다.
CSS 변경이 특정 뷰포트에서만 레이아웃을 깨뜨리는데, 유닛 테스트로는 잡을 수 없다. Visual QA는 스크린샷 비교로 시각적 회귀를 감지한다. dev-frontend의 visual-verification.md와 연동된다.
Triggers: test, TDD, coverage, CI gate, harness, E2E, visual QA, screenshot
Key Concepts
- Test Pyramid
- Harness Selection
- CI Gate Strategy
- TDD Workflow
- Coverage as Risk Signal
- Visual QA (screenshot verification)
Related Skills
Reference Documents
| Document | Description |
|---|---|
| Backend Testing Patterns | 백엔드 테스트 패턴: 서비스 레이어, DB, API 통합 테스트 |
| CI Pipeline Templates | CI 파이프라인에서의 테스트 게이트와 캐싱 전략 |
| Edge-First Testing Workflow | 엣지/서버리스 환경 테스트 패턴과 miniflare |
| Load & Performance Testing | 부하 테스트: k6, Artillery, 성능 기준선 설정 |
| ML Model Evaluation | ML 모델 평가: 메트릭, A/B 테스트, 데이터 드리프트 감지 |
Sections Overview
| Section | Summary |
|---|---|
| Test Pyramid | 유닛 > 통합 > E2E 비율과 각 계층의 역할을 정의한다. |
| Harness Selection | 프로젝트 스택에 맞는 테스트 프레임워크를 선택한다. |
| CI Gates | 커버리지 임계값, 테스트 실패 시 머지 차단 규칙. |
| TDD Workflow | Red-Green-Refactor 사이클과 적용 시점 판단. |
| Visual QA | 스크린샷 비교, 뷰포트별 검증, 시각적 회귀 방지. |
Academic References
| Paper | Year | Relevance |
|---|---|---|
Test Smells in LLM-Generated Unit TestsarXiv:2410.10628 | 2024 | LLM이 생성한 유닛 테스트의 테스트 스멜(anti-pattern) 분석. 가짜 테스트 문제의 실증. |
Do LLMs Generate Test Oracles That Capture the Actual or the Expected Program Behaviour?arXiv:2410.21136 | 2024 | LLM 테스트 오라클이 실제 동작 vs 기대 동작 중 무엇을 검증하는지 분석. |
TOGLL: Correct and Strong Test Oracle Generation with LLMsarXiv:2405.03786 | 2024 | LLM으로 정확하고 강력한 테스트 오라클을 생성하는 방법론. |
Disrupting Test Development with AI AssistantsarXiv:2411.02328 | 2024 | 테스트 피라미드 프레임워크로 AI 생성 유닛 테스트의 품질과 분포를 평가. |
The Ladder: A Reliable Leaderboard for ML Competitions (Blum & Hardt)arXiv:1502.04585 | 2015 | 튜닝 세트에서만 이기는 후보는 과적합. GATE-OVERFIT-01의 근거. |
The Reusable Holdout (Dwork et al.)arXiv:1506.02629 | 2015 | 홀드아웃 데이터를 재사용하면서 적응적 과적합을 방지하는 방법. |
Official Guides
- Vitest Documentation — Vite 네이티브 테스트 프레임워크 공식 가이드.
- Playwright Documentation — 크로스 브라우저 E2E 테스트 프레임워크 공식 가이드.
- pytest Documentation — Python 테스트 프레임워크 공식 가이드.
Full Specification
Show full SKILL.md content
Testing & QA
Balance: ~40% Backend/API, ~40% Frontend/E2E (Playwright), ~20% Cross-cutting (CI, Security, TDD, Coverage) -- directional guidance, not a hard ratio.
Scope: test harnesses, fixtures, mock policy, runners, Playwright, CI gates, coverage. Root-cause analysis and debugging playbooks → dev-debugging.
This skill activates by change surface when work needs verification depth, regression coverage, or a reproducible test harness.
> C0/C1 work (small local patches): See dev §0.0 Work Classifier + §0.1 Patch Fast-Path before reading references.
Modular References
| File | When to Read | What It Covers | |
|---|---|---|---|
references/core/crud-test-matrix.md | When choosing verification depth for a classified task, or testing a CRUD slice | Risk-tier minimums, per-operation negatives, UI smoke rule | |
references/edge-first-testing.md | New unit/service/integration tests for features (skip for regression/contract tests) | Edge-first principle, test order by change type, 11-class edge matrix | |
references/backend-testing.md | Backend/API testing | Supertest patterns, DB fixtures, auth mocking | |
references/ci-pipeline.md | CI configuration | GitHub Actions, gates, caching, parallelism | |
references/load-testing.md | Performance/load testing, C3+ production readiness | k6/Locust, test types, measure→profile→verify, CI gates |
references/ml-evaluation.md | ML model/LLM evaluation, quality gates | LLM-as-judge, RAGAS, DeepEval, CI eval gate, regression detection. CI eval gates are dataset-versioned + regression-based: pin prompts/models/retrieval config, preserve traces, calibrate judges on golden examples, fail only on meaningful regressions or safety failures |
When tests depend on current external API behavior, provider docs, CI service
behavior, test-environment versions, dependency audit evidence, or recorded
mock/fixture sources, read the active search skill and follow its
source-fetch and evidence-status rules.
---
1. Test Strategy
1.1 Models
| Model | Best For | Emphasis |
|---|---|---|
| Test Pyramid | monoliths, libraries | speed, isolation |
| Testing Trophy | modern web apps, REST backends | confidence-to-cost |
| Test Honeycomb | microservices, async systems | boundary verification |
1.2 Recommended Trophy Distribution
| Layer | Default Share | Typical Tools | |
|---|---|---|---|
| Static analysis | base layer | tsc, ESLint, mypy, Ruff | |
| Unit | ~25% | Vitest, Jest, pytest | |
| Integration | ~50% | Supertest, httpx, Testcontainers | |
| Contract | ~10% | Pact, OpenAPI validators, Schemathesis | |
| E2E | ~10% | Playwright |
| Manual / exploratory | ~5% | human review |
| Problem | Primary Harness | Avoid | |
|---|---|---|---|
| pure business rule | unit / service test | browser test | |
| route + middleware + serialization | API integration test | mocking the route itself | |
| DB query / migration / transaction | real DB integration test | fake repository for SQL correctness | |
| frontend consuming backend JSON | contract test | manual-only verification | |
| rendered critical flow | Playwright smoke | asserting internal React state |
| rendered artifact (visual correctness) | render-grounding loop (dev-pabcd C-RENDER-GROUNDING-01) | static parse / tsc alone |
| Technique | Use for | Default tools | When |
|---|---|---|---|
| Property-based | Pure logic, parsers, serializers, state machines, API invariants | fast-check (TS), Hypothesis (Python) | DEFAULT for invariant-heavy code |
| Mutation | Judging test-suite strength on critical domain logic, validators, security branches | Stryker (JS/TS), mutmut (Python) | Selective, after stable unit/property tests — not every PR |
- Vitest 4 is the current runner baseline: Browser Mode is stable (visual regression via
toMatchScreenshot, Playwright trace generation, expect.schemaMatching).
---
2. Backend & API Testing
> Deep reference: references/backend-testing.md
2.1 Coverage Map
| Layer | Verify | TypeScript Default | Python Default |
|---|---|---|---|
| Service layer | validation, orchestration, domain errors | Vitest | pytest |
| API layer | status, envelope, middleware, auth | Supertest | httpx / ASGITransport |
| Repository layer | SQL / ORM correctness | Testcontainers + real DB | Testcontainers + real DB |
| Background jobs | idempotency, retry, dead-letter | Vitest + fake clock | pytest + monkeypatch |
| Style | Best For | Tooling |
|---|---|---|
| consumer-driven contract | rapidly changing frontend/backend teams | Pact |
| schema-first contract | OpenAPI-led backends | OpenAPI validators, Schemathesis |
| type-level contract | TS monorepos | shared types / codegen |
| full-stack smoke | final user confidence | Playwright |
| Dimension | When to Use | |
|---|---|---|
| Node / Python version matrix | packages, SDKs, shared libraries | |
| OS matrix | native modules, CLI behavior | |
| shard matrix | large suites exceeding CI budget |
| Symptom | First Fix | |
|---|---|---|
| passes locally, fails in CI | deterministic seeds, containerized deps, explicit waits | |
| order-dependent failure | reset shared state in fixtures | |
| green on retry only | remove wall-clock / random assumptions | |
| screenshot noise | stable CI image, mask dynamic regions |
| Check | Pass Criteria | |
|---|---|---|
| Test written before implementation? | test file added / updated before or with code | |
| Failure observed before fix? | red state was actually executed | |
| Behavior-focused assertions? | checks outputs, side effects, contracts | |
| Regression locked in? | failing case is now protected by a persistent test |
| Style | Best For | |
|---|---|---|
| London / mockist | orchestration-heavy boundaries | |
| Chicago / classicist | domain logic and transforms | |
| Hybrid | most production code |
| Pattern | Description | Test Strategy |
|---|---|---|
| Sandbox/production mismatch | Fix applied to one code path, not both | Assert same response shape in both modes |
| SELECT clause omission | New field in response but missing from DB query | Assert all required fields are present and defined |
| Error state leakage | Error set but stale data not cleared | Assert state cleanup on error transitions |
| Missing rollback | Optimistic UI update without recovery on failure | Assert state restoration after simulated API error |
Regression Naming Convention
Name regression tests with BUG-R{N} convention. Assert all required fields with a loop.
Sandbox-Mode API Testing
When the project supports a sandbox/mock mode, use it for fast DB-free regression testing:
- Force sandbox mode in test setup:
process.env.SANDBOX_MODE = 'true' - Assert sandbox responses match the same contract as production responses.
- Treat sandbox/production parity as a high-priority regression target.
- In sandbox/spike mode, write tests for bugs found — coverage grows organically. For production refactors, see §1.5 (tests required for behavior changes).
---
6.7 Test-Induced Production Defense Detection
Rule: Do not add production defensive code solely to satisfy unrealistic tests. A production guard is allowed only when the invalid state can occur at a real boundary or represents an explicit domain rule.
| Production change smell | Likely test problem | Required action |
|---|---|---|
Internal if (!x) return added after unit test fails | Test fixture omitted required field | Fix fixture factory or test boundary validation |
| Required field made optional to satisfy test | Test is using invalid domain object | Restore required type and update test data |
| Catch-all added so test passes | Test expects silence instead of failure | Assert typed error or user-visible failure |
| Production default added for impossible state | Test bypassed constructor/parser | Use real constructor/parser in test |
| Private helper exported only for test | Test is coupled to implementation | Test public behavior or move helper to test support |
| Sleep/retry added only for test flake | Test lacks deterministic synchronization | Wait on observable condition or fake clock |
NODE_ENV === "test" branch added | Test-only production behavior | Remove branch; improve test harness |
Required questions before adding a guard:
- Is the input from an untrusted boundary? → If yes, validate at that boundary
- Can this state happen in production? → If no, fix the test
- What contract allows this value? → Cite schema/type/domain rule
- Would this hide a real bug? → If yes, fail fast instead
Banned patterns: process.env.NODE_ENV === "test" branches, silent fallbacks for impossible internal state, making required types optional for mocks, exporting internals only for tests.
Allowed guards: Boundary validation (process/network/user/file boundary), backward compatibility (documented old schema), security checks, domain invariants, observed production bug regressions, external dependency adapters.
---
7. Accessibility Testing
Component Level
- jest-axe / vitest-axe: run axe-core on rendered components
import { axe, toHaveNoViolations } from 'jest-axe'
expect.extend(toHaveNoViolations)
expect(await axe(container)).toHaveNoViolations()
Page Level
- Playwright a11y assertions:
import AxeBuilder from '@axe-core/playwright'
const results = await new AxeBuilder({ page }).analyze()
expect(results.violations).toEqual([])
CI Pipeline
- Gate order (verified 2026-07-02): component axe (jest-axe/vitest-axe) → page axe
(@axe-core/playwright) → keyboard/focus/manual checks. **Blocking gate = zero
serious/critical axe violations + targeted manual checks.**
- Lighthouse a11y score (≥90) is an advisory route-level smoke signal, NOT the blocking
gate — Lighthouse itself separates automated scoring from required manual checks.
- Pa11y: page-level scanning for WCAG AA violations
- Run a11y tests on EVERY page route, not just the homepage
Observability Verification
Verify trace propagation in integration tests. Assert that spans appear for critical paths. Check structured log format matches the schema in dev-backend/references/core/observability.md.
---
8. Security Testing
→ Delegated: threat modeling and secure design policy belong to dev-security.
This section covers the automated test hooks and CI gates that enforce those rules.
8.1 Minimum Security Stack
fast local checks
→ Semgrep / CodeQL gate
→ dependency audit
→ auth / validation regression tests
8.2 Dependency Scanning Commands
npm audit --audit-level=high
pip-audit --strict --desc
8.3 Semgrep Gate
The returntocorp/semgrep-action wrapper is deprecated (stated by the repo itself) —
run Semgrep natively in CI:
semgrep:
runs-on: ubuntu-latest
container: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- run: semgrep ci --config p/default --config p/javascript --config p/typescript --config p/python
(Open-source alternative engine: Opengrep, the LGPL-2.1 community fork — see
dev-security/references/static-analysis.md.)
8.4 Security Regressions
Test missing auth (expect 401) and verify error.code matches contract for every auth-protected endpoint.
8.5 Rules
- dependency audit in CI
- Semgrep or equivalent SAST
- auth / permission regression tests
- validation tests for malicious or malformed input
- a blocking rule for high / critical dependency findings
---
9. Coverage & Quality Gates
9.1 Suggested Thresholds
These are project/risk-based, not universal minimums. Adjust for your context.
| Metric | Suggested Floor | Ideal |
|---|---|---|
| Line coverage | 70% | 85%+ |
| Branch coverage | 60% | 80%+ |
| Function coverage | 80% | 90%+ |
| Diff coverage | 80% | 90%+ |
| Metric | Target |
|---|---|
| Defect detection rate | > 80% |
| Mean time to detect | < 1 CI run |
| Test signal-to-noise | > 95% |
| Contract drift rate | near 0 |