Test-Driven Development Skill
Overview
This skill module provides comprehensive TDD workflow guidance, including the RED-GREEN-REFACTOR cycle, quality gates, test patterns, and anti-patterns to avoid.
[CUSTOMIZE] Examples may use a sample stack. Adapt commands and tooling for your project while preserving the same TDD principles.
Iron Law of TDD
A behavior is not done until a failing test proves the need, passing tests prove correctness, and refactoring preserves green tests.
TDD Cycle: RED → GREEN → REFACTOR
- RED: Write a failing test that describes the expected behavior
- GREEN: Implement the minimum code to make the test pass
- REFACTOR: Improve code quality while keeping tests green
Quality Hierarchy
Quality gates are enforced in priority order:
| Priority | Gate | Tool | Threshold | Enforcement |
|---|---|---|---|---|
| 🥇 PRIMARY | Mutation Testing | [CUSTOMIZE] Mutation tool | ≥80% | Blocks merge |
| 🥈 SECONDARY | Code Coverage | [CUSTOMIZE] Coverage tool | ≥80% | Blocks merge |
| 🥉 BASELINE | Tests Pass | [CUSTOMIZE] Test runner | 100% | Always required |
Why this order?
- Code coverage can be 100% with weak assertions (tests run but don't verify)
- Mutation testing validates that tests actually catch bugs
- Both together ensure comprehensive, high-quality test suites
Core Testing Principles
- Test behavior, not implementation: Test what code should do, not how it does it
- No reflection hacks: Don't test private methods via reflection
- Test rules, not formulas: "higher values produce larger results" not exact arithmetic
- Keep test files focused: Split by behavior if tests become unwieldy
Collection / Iteration Coverage
For any function that iterates a persisted collection (getAll() or
for...of across repository results), the test plan must include at
least one 2-record scenario that verifies the loop applies semantics to
all members, not only the first or primary record.
- Single-record fixtures confirm field-level semantics.
- Multi-record fixtures confirm loop-level correctness.
What do you need help with?
TDD Phase:
- write - Writing tests first (RED phase)
- implement - Making tests pass (GREEN phase)
- validate - Running quality gates (coverage + mutation)
- refactor - Improving code while keeping tests green (REFACTOR phase)
- lookup - Reference information (patterns, commands, anti-patterns)
What phase are you in? (write/implement/validate/refactor/lookup)
Response Routing
| Response | Workflow/Reference | Description |
|---|---|---|
| write | workflows/write-tests-first.md | RED phase - write failing tests |
| implement | workflows/make-tests-pass.md | GREEN phase - implement code |
| validate | workflows/validate-coverage.md | Run quality gates |
| refactor | workflows/refactor-safely.md | REFACTOR phase - improve code |
| lookup patterns | references/test-patterns.md | AAA, parameterized tests, factories |
| lookup commands | references/commands.md | Test commands reference |
| lookup gates | references/quality-gates.md | Thresholds and enforcement |
| lookup anti-patterns | ## Gotchas (below) | Summary of what to avoid; see references/anti-patterns.md for detailed examples |
Reference Files
Workflows
workflows/write-tests-first.md- RED phase workflowworkflows/make-tests-pass.md- GREEN phase workflowworkflows/validate-coverage.md- Quality gate validationworkflows/refactor-safely.md- REFACTOR phase workflow
References
references/quality-gates.md- Mutation and coverage thresholdsreferences/test-patterns.md- AAA pattern, parameterized tests, factoriesreferences/anti-patterns.md- Common anti-patterns to avoidreferences/commands.md- Test and validation commands
Templates
templates/test-file.md- New test file structuretemplates/describe-block.md- Behavior-organized test structure
Quick Reference
# [CUSTOMIZE] Replace with your project's test commands
# Run tests
./gradlew test
# Run with coverage (JaCoCo)
./gradlew test jacocoTestReport
# Run mutation testing (PIT)
./gradlew pitest
Gotchas
| Trigger | Gotcha | Fix |
|---|---|---|
Testing a private method via reflection (setAccessible(true)) |
Couples test to implementation; breaks on rename or visibility change | Test through the public interface that exercises the private logic |
Asserting verify(repo, times(1)).findById(...) instead of the result |
Breaks on caching, batching, or any refactor — tests the mechanism, not the behavior | Assert on the returned result or observable side effect, not how it was obtained |
| Testing null/empty inputs that can never occur in the system | Bloats test suite; encourages defensive code that hides real bugs | Test realistic input ranges only; match edge cases to actual system boundaries |
assertThat(health).isEqualTo(150) with an exact formula match |
Breaks on any formula tweak; encodes the implementation, not the business rule | Test comparative invariant (highVit.health > lowVit.health) not exact values |
| 100% line coverage with assertions that don't verify correctness | Coverage is green; mutations survive | Run mutation testing; require ≥80% score; review asserts on each changed line |
| Organizing tests as one method per production method | Misses behavior variations and error cases; becomes a checklist | Organize by scenario/behavior with descriptive names; use @Nested groups |
For detailed examples of each anti-pattern, see references/anti-patterns.md.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.