Skip to main content

test-design-advisor

Worker skill — assess testability, recommend the right test-pyramid layer and test-double strategy, and propose a behavior-preserving refactor sequence to make hard-to-test code testable. Invoked by /test-design and /test-health; not user-invocable. For a user-facing entry point use /test-design (add --advise --path <file> for forward-design on a single unit).

Source facts

Repository
bdfinst/agentic-dev-team
Last source activity
July 31, 2026 at 12:40
Detected SKILL.md language
English
Stars
295
Forks
36

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
test-design-advisor
description
Worker skill — assess testability, recommend the right test-pyramid layer and test-double strategy, and propose a behavior-preserving refactor sequence to make hard-to-test code testable. Invoked by /test-design and /test-health; not user-invocable. For a user-facing entry point use /test-design (add --advise --path <file> for forward-design on a single unit).
role
worker
# Test Design Advisor ## Overview An **advisory** skill: it recommends how to test code and how to make untestable code testable. It does not write tests or refactor code — it produces a design the human (or `/build`) then implements. Use it before writing a test suite for an untested or hard-to-test module, or when a test is hard to write and you suspect the design is the cause. Grounded in these knowledge references: `knowledge/test-smells.md`, `knowledge/test-doubles.md`, `knowledge/test-pyramid.md` (layers + shapes), `knowledge/test-layer-gates.md` for behavior pre-gates, `knowledge/microservice-testing.md`, `knowledge/testability-patterns.md` for production-code seams, and `knowledge/test-strategy.md` for fixture and SUT-interaction strategy. For the xUnit pattern families it grounds in `knowledge/fixture-construction.md` (how the fixture is built/disposed), `knowledge/value-patterns.md` (Literal/Derived/Generated Value + Dummy Object for test data), `knowledge/result-verification.md` (assertion patterns), `knowledge/test-organization.md` (Four-Phase + suite structure), `knowledge/test-refactoring.md` (goals/principles + the test-side refactoring catalog), and `knowledge/test-automation-principles.md` (the goals/principles a recommendation must honor — the rubric behind every "why"). When the target is untested legacy code, it grounds the get-under-test-first sequence in `knowledge/dependency-breaking-techniques.md` (behavior-preserving seams) and `knowledge/legacy-test-strategy.md` (effect/pinch reasoning for where to place the tests). On match it overlays `knowledge/testing-techniques/` (specialized techniques), resolves tools from `knowledge/test-stack-profiles/<stack>.md`, and may adapt a worked template from `knowledge/test-matrix-examples/`. ## Constraints - Advisory only. Do not edit production code or write test files — output a recommendation. - A hard-to-test design is a production-code problem. Recommend the seam (constructor injection, interface extraction), never a test workaround (reflection, `InternalsVisibleTo`, mocking concrete classes). - Prefer the lowest test-pyramid layer that can verify the behavior; prefer state verification and the simplest double. - Refactor sequences must be behavior-preserving and start with characterization tests when the code is currently untested. - Be concise: tables and ordered steps, not prose. No restating the source material — cite the knowledge file. - **Altitude boundary.** When a gate mandates application-level E2E/browser architecture, flag the seam (`→ cd-test-architecture`) and defer the harness/pipeline design to the `cd-test-architecture` skill — do not design the E2E harness here. - **Vocabulary (MinimumCD).** Use the six MinimumCD test types defined in `knowledge/cd-test-architecture.md` § *The Six Test Types*: **static analysis / unit / component / contract / integration / E2E**. **"Contract test"** is the primary term — use it. When the codebase or external context calls it a **"narrow integration test"**, gloss it once in the same sentence: `contract test (also called narrow integration test)`. Never use "narrow integration" alone. When the codebase uses different names for layers (e.g. "service test", "API test", "scenario test"), emit a **Terminology mapping** table at the top of the report and then use the MinimumCD term consistently from that point. - **Test type definitions.** When the report mentions any of {unit, component, contract, integration, E2E, static analysis, sociable unit, solitary unit, resilience}, define each term on first use — either inline as a one-line gloss or in a small **Test type definitions used in this report** block at the top. Definitions come verbatim from `knowledge/cd-test-architecture.md` § *The Six Test Types*. - **The pyramid is a cost heuristic, not a target shape** — canonical rule in `knowledge/cd-test-architecture.md#the-pyramid-is-a-cost-heuristic-not-a-target-shape`. No "current shape vs recommended shape" tables and no per-layer target counts; place each behavior at the lowest layer that can verify it. - **E2E justification gate** — canonical in `knowledge/cd-test-architecture.md#the-e2e-justification-gate`. Recommend E2E only when all four conditions hold, and surface the four-condition verdict in the E2E justification table (Output). ## Parse Arguments Arguments: target file(s), module, or a description of the code to test. If no target is given, ask for one. Detect language **and framework/stack** (from manifests — `package.json`, `build.gradle`/`pom.xml`, `*.csproj`, `go.mod`, `requirements.txt`/`pyproject.toml`, and frontend deps like react/vue/htmx) so tool resolution can pick the right `test-stack-profiles/<stack>.md`. Detect whether the target crosses independently-deployable service boundaries (load `microservice-testing.md` only if so). ## Steps ### 1. Assess testability Read the target. For each unit, determine whether it can be constructed and driven through its public API with controlled inputs. Use the decision flow in `knowledge/testability-patterns.md`. Record blockers: static factories/singletons, new-ed-up dependencies, hidden global/clock/RNG access, concrete-class coupling, private logic with no public path. **Graph-assisted testability assessment.** Prefer CodeGraph/Repowise over raw `Grep`/`Read` for finding the unit's collaborators, its callers, and blast radius before recommending a seam — see [`knowledge/codegraph-vs-graphify.md`](../../knowledge/codegraph-vs-graphify.md) for tool selection and the fallback contract. ### 1b. Behavior pre-gates (escalate the layer by failure mode) Before pyramid placement, run the gates in `knowledge/test-layer-gates.md`. They **escalate upward only** — never lower the Step 2 pick; silent when none fire: - **Gate A** user-facing dynamic → E2E alongside lower layers (state cost + amortization) - **Gate B** bug fix → regression at the discovery layer (no escalation above it) - **Gate C** HTMX/Alpine/Turbo swap → browser test REQUIRED for the seam - **Gate D** visual artifact → approval/screenshot (with a reference) or manual If dynamic-ness is ambiguous, state your assumption and ask **once** (batch ambiguities; offer "treat all as dynamic") — never escalate silently. When a gate mandates app-level E2E, flag it `→ cd-test-architecture` and defer the harness design there. ### 2. Place each behavior on the pyramid Using `knowledge/test-pyramid.md`, assign each behavior to the lowest layer that can meaningfully verify it (unit / component / contract / integration / E2E — MinimumCD names per the Vocabulary constraint). Flag anything currently mis-layered. For service boundaries, apply contract testing per `knowledge/microservice-testing.md` instead of E2E. For any behavior placed at integration or E2E, the E2E justification gate (Constraints) MUST be satisfied and the four-condition verdict surfaced in the report. **Two-direction justification.** The placement table's *Why this layer* column carries a two-direction justification: when the pick is unit or component, explain why a higher layer would be redundant or cupcake-shaped duplication; when the pick is integration or E2E, explain why a contract or component test cannot cover the behavior. The advisor must articulate the trade-off rather than pattern-match a layer. **No target counts.** Do NOT emit a "current shape vs recommended shape" table or any per-layer target count. Per-behavior placement is the only valid output for layer recommendations (see the Constraints: *The pyramid is a cost heuristic, not a target shape*). **Redundancy check (business-critical only).** After placement, for any behavior determined business-critical (labelled, or confirm by asking), if it is covered at only one layer, flag it and name a second layer with a different failure mode (catches/misses table in `test-layer-gates.md`) plus a concrete recommendation. **Gate-column output schema.** In the *Pyramid placement* table the `Gate` column uses: `—` (no gate), `↑<layer>` (escalated), `→ cd-test-architecture` (E2E architecture deferred). When multiple gates fire, union the layers (no duplicate) and list each gate's cost once, with reconciliation guidance if the amortization advice differs. **Tool resolution (by detected stack).** After the layer is fixed, name the concrete tool. If the detected stack has a profile in `knowledge/test-stack-profiles/<stack>.md`, read it and fill the `Tool` column from its layer→tool map (e.g. Spring integration → MockMvc; SSR frontend → JSDOM+MSW, **not** a browser unit runner). If no profile matches, proceed with stack-agnostic guidance and **name the missing profile** in the report — never block on it. **Few-shot templates.** When building a multi-behavior matrix for a common stack, you *may* load a worked example from `knowledge/test-matrix-examples/` as a template and adapt its rows — never copy it verbatim. ### 2b. Specialized technique overlay (on trigger match) Some behaviors break in a way no pyramid layer addresses. Consult `knowledge/testing-techniques/` and add a technique **only when its trigger matches** — silent otherwise. Each overlay note states the technique and its maintenance cost; it complements (does not replace) the layer pick. | Trigger | Overlay | File | |---------|---------|------| | Invariant/law holds for all inputs | property-based | `property-based.md` | | Parses untrusted/unstructured input | fuzz | `fuzz.md` | | Large text/structured artifact vs a reference | approval | `approval.md` | | Visual/CSS/layout fidelity matters | screenshot | `screenshot.md` | | Payload governed by a declared schema (OpenAPI/JSON Schema/Avro) | schema-validation | `schema-validation.md` | | Resilience claim under dependency failure | chaos | `chaos.md` | **Exclusion.** Do **not** add a contract-testing technique here. Consumer↔provider agreement across an owned service boundary routes to `knowledge/microservice-testing.md` (CDC) — never double-route. ### 3. Choose doubles For each collaborator at each test, recommend the simplest double using the decision flow in `knowledge/test-doubles.md` (dummy/stub/spy/mock/fake) and whether to verify by state or behavior. Default to state verification + stub/fake; reserve mock/spy for true side-effect boundaries. ### 3b. Recommend fixture and interaction strategy **Under `/test-design`**, the smell agent has already named the smell and its remedy family (via `remedyFamily`, per `knowledge/test-review-division-of-labor.md` § "test-smell-review ↔ test-design-advisor — remedy division"); this step supplies the specific remedy pattern from that family and its per-behavior application. When invoked standalone, this step supplies both the smell framing and the pattern. Using `knowledge/test-strategy.md`, recommend per test group: fixture design + lifecycle (default Minimal + Fresh; escalate to Immutable Shared → Shared only under measured speed pressure), how the test is driven (scripted default; data-driven when variation is purely data), and SUT interaction (front-door by default; Layer Test for layered code; Back Door Manipulation only when the front door obscures intent). Flag any reliance on a mutable Shared Fixture as an Interacting-Tests risk. For the construction **mechanics** that realize that strategy, recommend a specific pattern from `knowledge/fixture-construction.md` — Creation Method / Test Data Builder / Object Mother for building, the right setup location, and **Automated Teardown** for persistent fixtures — to fix fixture smells (Mystery Guest, General Fixture, Irrelevant Information, Test Code Duplication) at the root rather than only naming them. ### 3c. Recommend verification and test structure **Under `/test-design`**, the smell agent has already named the smell and its remedy family (via `remedyFamily`, per `knowledge/test-review-division-of-labor.md` § "test-smell-review ↔ test-design-advisor — remedy division"); this step supplies the specific remedy pattern from that family (result-verification and test-organization patterns) and its per-behavior application. Using `knowledge/result-verification.md`, recommend the assertion pattern that fixes verification smells: **Expected Object** for field-by-field clutter, **Custom Assertion / Verification Method** for repeated complex comparisons or poor failure messages, **Guard Assertion** before a precondition-dependent assertion, **Delta Assertion** against a baseline for shared/persistent fixtures — and verify one logical condition per test. Using `knowledge/test-organization.md`, recommend test/suite structure: make the **Four-Phase Test** (Setup → Exercise → Verify → Teardown) visible, group **Testcase Class per Class / Feature / Fixture** when setups diverge, share via a **Test Utility Method / Helper** (composition) over a **Testcase Superclass** (inheritance), and collapse data-only duplication into a **Parameterized Test**. ### 4. Propose a behavior-preserving refactor sequence (only if blockers or test smells exist) If Step 1 found blockers in **production** code, produce an ordered sequence that makes it testable without changing behavior: 1. Add characterization tests around current behavior (if untested) — pin existing behavior first. 2. Introduce the seam (the specific pattern from `testability-patterns.md`). 3. Write the now-possible tests at the layer from Step 2. 4. Refactor under green. When the smell is in the **test** itself (not production code), name the specific behavior-preserving move from `knowledge/test-refactoring.md` that removes the smell and shifts the test toward the violated goal/principle — e.g. *Inline Mystery Guest* → Fresh Fixture via Creation Method, *Replace General Fixture with Minimal Fixture*, *Introduce Expected Object*, *Extract Custom Assertion*, *Split Test*. Test refactorings are behavior-preserving and **characterization-first** when the target is untested. Each step names the pattern and the exact change required. ### 5. Report Write the recommendation (see Output). Keep it actionable — every recommendation maps to a concrete next edit. ## Output A concise advisory report (to chat for a single unit, or to `.dev-team-reports/test-design-<target>.md` for a module): ```markdown ## Test Design — <target> ### Test type definitions used in this report <one-line glosses for every MinimumCD term used below; verbatim from `knowledge/cd-test-architecture.md` § The Six Test Types> ### Terminology mapping (only if the codebase uses non-MinimumCD names) | Local name | MinimumCD term | ### Testability | Unit | Testable as-is? | Blocker | Seam (testability-patterns.md) | ### Pyramid placement | Behavior | Layer | Gate | Tool | Why this layer (not the one above or below) | (`Tool` from the stack profile, or `—` / "no profile: <stack>" when none matches. *Why this layer* MUST be two-direction: unit/component picks justify why higher would be redundant; integration/E2E picks justify why contract/component cannot cover the behavior.) ### E2E justification (only when a behavior is placed at E2E) | Behavior | (1) Contract test ruled out — why | (2) Component test ruled out — why | (3) Resilience test ruled out — why | (4) User journey + multi-component rationale | Pipeline stage | ### Technique overlay (only if a trigger fired) | Behavior | Technique | Cost note | ### Double strategy | Test | Collaborator | Double | Verify by | ### Refactor sequence (if blockers) 1. <characterization tests> → 2. <seam> → 3. <tests> → 4. <refactor> ### Next edit <the single concrete first action> ``` **Do NOT emit a "current shape vs recommended shape" table or any per-layer target count.** The pyramid is a cost heuristic; per-behavior placement is the only valid layer output. See Constraints. ## Integration - Pairs with the `test-smell-review` agent (which *detects* smells) and the `farley-score` skill (which *scores* an existing suite). This skill *designs* tests forward. - For application-level test architecture (CD pipeline alignment, deterministic config-free CI gate, per-component UI/service/batch patterns), defer to the `cd-test-architecture` skill and its knowledge files (`cd-test-architecture.md`, `component-test-patterns.md`). This skill stays at unit/module altitude. - Hand the refactor sequence to `/plan` or `/build` for TDD implementation. This skill stops at the design.
View on GitHub