ワンクリックで
test-driven-development
TDD: enforce RED-GREEN-REFACTOR, tests before code, traceable trust, and test-suite hygiene.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
TDD: enforce RED-GREEN-REFACTOR, tests before code, traceable trust, and test-suite hygiene.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
General-purpose code review standard: test real logic, fail loud on configuration errors, no meaningless fallbacks, structural decomposition for testability. Use when reviewing any code change.
General-purpose code review standard: test real logic, fail loud on configuration errors, no meaningless fallbacks, structural decomposition for testability. Use when reviewing any code change.
Guided task execution for the Executor role. Use when the Executor claims a task from the orchestrator queue and needs to execute it — reading the blueprint, making code changes, running verification, and reporting results with full traceability from every code change back to the Plan. Triggers on keywords like "执行任务", "开始构建", "claim task", "execute", "implement", "开发", "写代码", or when an Executor has claimed a task and is ready to work. Complements task-traceability as the foundational traceability layer.
Magic-loop terminator. Use when a chain reaches the explore link (only present under `--magic`) and the Explorer must decide between `spawn_chain` (open a follow-up chain with a concrete `next_requirement`) and `close_chain` (terminate the autonomous loop). Triggers on keywords like "explore link", "spawn_chain", "magic loop", "next iteration", "autonomous follow-up". The skill enforces evidence-traced reasoning over speculation and respects the `--magic-max-chains` depth cap.
TDD: enforce RED-GREEN-REFACTOR, tests before code.
Multi-agent orchestration system reference for Workers. Covers the v0.4 unified run command, worktree isolation, directory memory (CLAUDE.md), responsibility chain (Plan→Build→Verify→Review→Accept), output standards, and common pitfalls. Use this skill whenever a Worker executes any link in the responsibility chain — read it at session start and whenever you are unsure about process, output paths, or role boundaries.
| name | test-driven-development |
| description | TDD: enforce RED-GREEN-REFACTOR, tests before code, traceable trust, and test-suite hygiene. |
| version | 2.0.0 |
| author | Adamancy Zhang |
| license | MIT |
Write the test first. Watch it fail. Write minimal code to pass. Keep the test suite from rotting.
Three core principles:
Violating the letter of the rules is violating the spirit of the rules.
Always:
Exceptions (ask the user first):
Thinking "skip TDD just this once"? Stop. That's rationalization.
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Write code before the test? Delete it. Start over.
No exceptions:
Implement fresh from tests. Period.
Write one minimal test showing what should happen.
Good test:
def test_retries_failed_operations_3_times():
attempts = 0
def operation():
nonlocal attempts
attempts += 1
if attempts < 3:
raise Exception('fail')
return 'success'
result = retry_operation(operation)
assert result == 'success'
assert attempts == 3
Clear name, tests real behavior, one thing.
Bad test:
def test_retry_works():
mock = MagicMock()
mock.side_effect = [Exception(), Exception(), 'success']
result = retry_operation(mock)
assert result == 'success' # What about retry count? Timing?
Vague name, tests mock not real code.
Requirements:
MANDATORY. Never skip.
# Run the specific test
<project-test-runner> <test-file>::<test-name>
Confirm:
Test passes immediately? You're testing existing behavior. Fix the test.
Test errors? Fix the error, re-run until it fails correctly.
Write the simplest code to pass the test. Nothing more.
Good:
def add(a, b):
return a + b # Nothing extra
Bad:
def add(a, b):
result = a + b
logging.info(f"Adding {a} + {b} = {result}") # Extra!
return result
Don't add features, refactor other code, or "improve" beyond the test.
Cheating is OK in GREEN:
We'll fix it in REFACTOR.
MANDATORY.
# Run the specific test
<project-test-runner> <test-file>::<test-name>
# Then run ALL related tests to check for regressions
<project-test-runner> <test-directory>/
Confirm:
Test fails? Fix the code, not the test.
Other tests fail? Fix regressions now.
After green only:
Keep tests green throughout. Don't add behavior.
If tests fail during refactor: Undo immediately. Take smaller steps.
Next failing test for next behavior. One cycle at a time.
TDD produces tests. Ungoverned tests rot. Every test you write belongs to one of two categories:
A test that guards a critical behavior. It earns its place permanently.
When a test qualifies as core:
Core test obligations:
# CORE-RETENTION
# Locks in: <one sentence describing the observable behavior>.
# Critical because: <what breaks if this regresses>.
# Primary sources: <file paths>.
A test without this header is subject to deletion during any triage pass.
Tests written during active development that haven't proven their lasting value.
Scratch test rules:
tests/scratch/YYYY-MM-DD/<feature>/)Promotion to core: When a scratch test proves it covers a meaningful behavioral invariant:
Why this distinction matters: Without it, every test is permanent by default. The suite accumulates one-off experiments, half-finished explorations, and tests that passed once and were never touched again. Developers stop trusting the suite. Then they stop running it. Then they stop writing tests.
Core vs scratch is not bureaucracy — it's the difference between a curated library and a junk drawer.
Every mock is a lie. You're replacing a real dependency with a fake one. The question is whether the lie is justified and documented.
A mocked test that passes while the real dependency is broken is a false negative — the most dangerous kind of test. It tells you everything is fine while production burns.
Before mocking any dependency, complete this review:
The canonical acceptable case: external API calls, subprocess invocations, or expensive I/O where the cost (time, money, flakiness) of real execution outweighs the risk of the mock. The protocol contract — "we send X, we expect Y-shaped response" — is the trust boundary.
Every mock must carry a comment immediately above it:
TRUST-JUSTIFICATION: Mocking <module-or-function>.
Downstream: <what is being skipped>.
Reason: <why the real dependency is not exercised here>.
Evidence: <what covers the real downstream — an integration test,
a manual smoke test, a contract assertion, or a known
external guarantee>.
Example:
# TRUST-JUSTIFICATION: Mocking stripe.Charge.create.
# Downstream: Stripe API — real HTTP call to payment processor.
# Reason: Real calls cost money (~$0.30) and require network; running
# them in unit tests is impractical and non-deterministic.
# Evidence: The full payment flow is exercised in tests/integration/stripe/
# using Stripe's test mode. Here we assert only that the correct charge
# amount and currency are passed — the protocol contract between our
# code and the Stripe SDK.
No TRUST-JUSTIFICATION, no mock. A mock without justification is technical debt you can't see.
Do not add defensive try/catch in tests. Let unexpected failures surface as test failures. Errors are signal, not noise to be silenced.
# GOOD — error surfaces naturally
result = service.process(invalid_input)
assert result.status == "error"
# BAD — swallows the error, test passes when it shouldn't
try:
service.process(invalid_input)
except Exception:
pass # "I expected it might fail" — did it fail the RIGHT way?
Coverage percentage is NOT the goal. Observable-behavior testing is.
Assert on externally visible effects:
Do NOT assert on:
expect(fn).toHaveBeenCalledTimes(3))# GOOD — asserts on observable result
result = pipeline.process(input_data)
assert result.errors == []
assert len(result.items) == 5
# BAD — asserts on internal implementation
assert pipeline._cache.hits == 3
assert pipeline._validator.was_called
If changing the implementation without changing the behavior breaks your test, you tested the wrong thing.
A test that's painful to write is telling you something about the design:
| Test Pain | Design Problem |
|---|---|
| Don't know how to test | Interface is unclear |
| Test too complicated | Design too complicated |
| Must mock everything | Code too coupled |
| Test setup is huge | Missing abstractions |
Listen to the test. Fix the design, not the test.
Not every change requires running every test. But misjudging scope causes regressions.
| Change touches | Minimum scope |
|---|---|
| Shared infrastructure (config, auth, logging, database client) | Full test suite |
| Cross-module contract (API schema, data format, protocol) | Full test suite |
| Single module internals | Unit tests for that module |
| New feature (isolated) | Unit tests for the feature + integration test at boundary |
| Bug fix | Test reproducing the bug + unit tests for the fix + check for related cases |
| Refactoring (no behavior change) | Existing tests must still pass; no new tests required |
| Documentation / config only | No tests required |
Run the full suite. A minute of CI time is cheaper than a regression in production.
Tests must not leak state into each other. A test whose outcome depends on run order is a lie waiting to surface.
Rules:
# GOOD — isolated
TEST_DB = f"test_{uuid4().hex}"
db = create_database(TEST_DB)
yield db
drop_database(TEST_DB)
# BAD — shared state leaks
db = connect_to("test_db") # All tests share this
"I'll write tests after to verify it works"
Tests written after code pass immediately. Passing immediately proves nothing:
Test-first forces you to see the test fail, proving it actually tests something.
"I already manually tested all the edge cases"
Manual testing is ad-hoc. You think you tested everything but:
Automated tests are systematic. They run the same way every time.
"Deleting X hours of work is wasteful"
Sunk cost fallacy. The time is already gone. Your choice now:
The "waste" is keeping code you can't trust.
"TDD is dogmatic, being pragmatic means adapting"
TDD IS pragmatic:
"Pragmatic" shortcuts = debugging in production = slower.
"Tests after achieve the same goals — it's spirit not ritual"
No. Tests-after answer "What does this do?" Tests-first answer "What should this do?"
Tests-after are biased by your implementation. You test what you built, not what's required. Tests-first force edge case discovery before implementing.
| Excuse | Reality |
|---|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to the test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. |
| "Existing code has no tests" | You're improving it. Add tests for the code you touch. |
| "Mock is fine, it's obvious why" | No TRUST-JUSTIFICATION, no mock. Obvious to you ≠ obvious in 6 months. |
| "This test is temporary" | Then put it in scratch/ with a date. "Temporary" without a delete-by date is permanent. |
| "Coverage is high, we're good" | Coverage measures execution, not verification. 100% coverage with bad assertions = 0% confidence. |
If you catch yourself doing any of these, delete the code and restart with TDD:
All of these mean: Delete code. Start over with TDD.
Before marking work complete:
Can't check all boxes? You skipped something. Start over.
| Problem | Solution |
|---|---|
| Don't know how to test | Write the wished-for API. Write the assertion first. Ask the user. |
| Test too complicated | Design too complicated. Simplify the interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup huge | Extract helpers. Still complex? Simplify the design. |
| Not sure if test is core or scratch | Default to scratch. Promote later if it proves its worth. |
| Not sure if mock is justified | It probably isn't. Write the TRUST-JUSTIFICATION — if you can't fill the Evidence field, don't mock. |
Production code → test exists and failed first
Core test → CORE-RETENTION header present
Mock → TRUST-JUSTIFICATION recorded
Scratch test → dated directory, deleted within window
Otherwise → not TDD
No exceptions without the user's explicit permission.