graph-tests
Test strategy audit using Test Pyramid, FIRST principles, coverage analysis, and test quality assessment
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Test strategy audit using Test Pyramid, FIRST principles, coverage analysis, and test quality assessment
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Accessibility compliance audit using WCAG 2.2 AA standards, ARIA validation, screen reader testing, keyboard navigation, color contrast analysis, and i18n readiness
Execute the ANALYZE phase of the lifecycle via the `agf` CLI — PRD creation, requirements, Definition of Ready (7 checks), cross-project learning
API governance and design audit using OpenAPI/Swagger spec generation, REST maturity model, contract validation, and breaking change detection
Architecture governance using C4 Model, ADR lifecycle, Architecture Fitness Functions, layer boundary enforcement, and drift detection
Human-in-the-loop PLANNING skill — investigates the project (graph + git + harness/gaps) and runs the whole ANALYZE→DESIGN→PLAN chain in one faceted loop to produce a COMPLETE PRD injected as graph backlog (epics, tasks, testable AC) for a separate agent to implement. Applies the project's planning methodologies — Impact Mapping + OKR per epic, JTBD, MoSCoW, WSJF/Cost-of-Delay, User Story Mapping, Example Mapping (Rules/Examples → Given-When-Then AC), SPIDR splitting, INVEST, Definition of Ready, Risk Matrix; the full catalogue lives in the skill body. Stops for the human after each complete PRD and iterates the next cycle from the project's own findings (dogfood). Does NOT implement. Triggers — graph-backlog-generation, gerar backlog, criar PRD, planejar feature, detalhar épico, novo ciclo, "plan the next thing", "what should we build next".
Automated bug discovery through static analysis, LSP diagnostics, pattern detection, regression hotspot analysis, and error catalog mining
| name | graph-tests |
| description | Test strategy audit using Test Pyramid, FIRST principles, coverage analysis, and test quality assessment |
| triggers | ["graph-tests"] |
| version | 2.0.0 |
| author | Diego Nogueira |
| date | "2026-06-21T00:00:00.000Z" |
Test strategy audit using Test Pyramid, FIRST principles, coverage analysis, and test quality assessment. Identifies gaps in test coverage, validates pyramid shape, ensures TDD discipline, and applies canonical test double and smell detection from Khorikov, Meszaros, and Freeman & Pryce.
npm test --> coverage report --> pyramid check --> FIRST audit --> test double audit --> smell scan --> missing tests --> test quality --> edge cases --> report --> write_memory
Run the full test suite. All tests must pass with zero failures.
npm test
If any test fails, STOP. Fix failures before proceeding. Never audit quality on a broken suite.
Fast inner-loop gate (agf ≥ 0.20.0): agf test --blast selects tests by code-impact radius — it walks the module graph from your uncommitted changes and runs only the transitively-affected tests. When nothing changed it takes a no-op fast path (no test process spawned). Use it during RED/GREEN iteration and at the agf done task gate; reserve the full npm test for the PR gate.
npm run test:coverage
Thresholds:
Report all files below threshold. Identify the top 5 modules with lowest coverage as priority targets.
Count tests by type to verify pyramid shape:
src/tests/*.test.ts without database/store dependenciesSqliteStore, in-memory database, or cross-module interactionssrc/tests/e2e/*.test.ts (Playwright browser tests)Healthy ratio target: ~70% unit, ~20% integration, ~10% E2E.
Flag inverted pyramids where integration or E2E tests outnumber unit tests.
Score each principle 0–100. Overall FIRST score = average.
| Principle | Criteria for 100 | Deductions |
|---|---|---|
| Fast | Every test < 1s; no sleep/setTimeout; no network calls | −20 per test > 1s; −30 for network I/O |
| Independent | Each test creates its own store/state; beforeEach resets; no shared mutable variables | −25 per shared-state leak found |
| Repeatable | Same result on every machine/run; no reliance on external services or file system; no Date.now() hardcoded | −30 for flaky test found |
| Self-validating | Clear assertions with descriptive messages; no console inspection needed; test passes = green, fails = red | −20 for undescribed assertion; −30 for "manual check" comment |
| Timely | Test exists in the same commit as the feature (TDD); no untested public functions in recently modified files | −10 per public function added without a corresponding test |
Score each principle 0–100. Overall FIRST score = average.
When code under test needs a collaborator, choose the right double (Meszaros taxonomy):
| Double | When to use | Assert on it? |
|---|---|---|
| Dummy | Parameter required but never used by the test's behavior | No |
| Stub | SUT needs a return value from a dependency (query); you don't care whether the call happened | No — never |
| Spy | You want to assert after the fact that a call occurred, without upfront expectations | Yes — in the Assert phase |
| Mock | You need pre-programmed expectations on outgoing commands; failure if call doesn't happen | Yes — verified automatically |
| Fake | You need a real working implementation (e.g., :memory: SQLite) without the real infrastructure cost | No |
Decision rule (Khorikov): Only mock unmanaged dependencies — services your application doesn't own and whose interactions are visible externally (SMTP, message bus, third-party APIs). Use real implementations (Fake/in-memory) for managed dependencies (SQLite store, in-process DB). Never mock intra-system calls between domain classes — those are implementation details.
For this project: Prefer Fake (:memory: SQLite via SqliteStore) for store tests. Use Stub for external API responses. Reserve Mock for verifying outgoing MCP tool calls.
Scan test files for these smells (Meszaros) and flag each one:
| Smell | Detection signal | Fix |
|---|---|---|
| Assertion Roulette | Multiple assertions, none with messages; when one fails you can't tell which | One behavior per test, or add assertion messages |
| Mystery Guest | Test reads from a file, global, or preset DB row not declared in the test body | Move setup inline or into a named Creation Method |
| Obscure Test | Hard to understand the scenario in under 10 seconds | Inline the relevant context; use a Test Data Builder |
| Eager Test | One test exercises 3+ distinct behaviors | Split into single-behavior tests |
| Erratic Test | Passes sometimes, fails other times (flaky) | Fresh Fixture; remove shared mutable state; eliminate Date.now() hardcoding |
| Fragile Test | Breaks when production code is refactored but behavior is unchanged | Stop testing implementation details; test through public API only |
| Interacting Tests | One test's side effect corrupts the next | beforeEach reset; Transaction Rollback or fresh :memory: DB per test |
| Hard-Coded Test Data | Literal magic values with no context (42, "abc", user1) | Named constants or factory helpers from src/tests/helpers/factories.ts |
| Overspecified Software | Mocks have expectations on every method call, including queries | allowing(...) for queries; oneOf(...) / Verify only for the one command under test |
Apply the right school per object type (Khorikov + GOOS):
| Object type | School | Strategy |
|---|---|---|
| Pure function / domain logic | Classical | No mocks; assert on return value |
| Domain object with state | Classical | Assert on state after act |
| Orchestrator (application service) calling unmanaged deps | London | Mock the external boundary; assert the command was sent |
| Orchestrator calling managed deps (SQLite store) | Classical | Use real in-memory store (Fake) |
Decision rule: If you'd write expect(result).toBe(...) on a return value → Classical. If correct behavior IS "it called X on Y with these args" → London. Never use London school for intra-system calls between domain classes.
For each modified .ts file in src/core/ and src/mcp/, check if a corresponding .test.ts exists in src/tests/.
agf tdd-score <id> # 0–100: coverage, assertion diversity, test density
agf verify-ac <id> # is the AC already satisfied by code that exists?
agf check <id> # Definition of Done, including TDD adherence
List all public exported functions without corresponding test assertions.
if in tests: An if = two behaviors. Split the test.:memory: SQLite, temp files) over mocks for store tests.makeNode, makeEdge from src/tests/helpers/factories.ts.returns_next_unblocked_task_sorted_by_priority, not getTask_validInput_returnsTask).beforeEach/afterEach cleanup; no leaked state.For each function under test, verify coverage of:
Test Suite: <N> tests, <N> passed, <N> failed
Coverage: statements <N>%, branches <N>%, functions <N>%, lines <N>%
Pyramid: unit <N> / integration <N> / e2e <N> (ratio: <X>:<Y>:<Z>)
FIRST Score: <N>/100 (F:<N> I:<N> R:<N> S:<N> T:<N>)
Test Smells: <N> found — [list by type]
Test Double Issues: <N> violations (over-mocked managed deps, stub assertions)
Gaps: <N> modules without tests
Grade: <A-F>
Grading:
Save findings:
agf memory write test-audit-<date> --content "<report>"
:memory: SQLite over mocks for store testsif statements in tests — split into separate test casesif in a test means two tests are needed.Economia de tokens. Os levers compartilhados por todas as skills —
--select,agf retrieve-command,agf exec chain, reuso antes de criação — vivem em_shared.md→ Token Economy. Fonte única: um parágrafo repetido em trinta arquivos é o trigésimo primeiro que envelhece sozinho.
Não precisa de flags. CLI gerencia compressão automaticamente com --ai ativo.
Consulte comandos com agf retrieve-command "<intenção>".
Ver _agf-rag.md para detalhes.