What is test-driven-development?
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
event4u-app/agent-config
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/test-driven-development"Quick start
Install it or open the source, trigger it with a clear task, then follow the source workflow.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/test-driven-development"Use test-driven-development to help me with: [describe your task]. Before you begin, tell me what input you need, the steps you will follow, and the expected output.
No structured workflow was detected; follow the original SKILL.md below.
Continue to the workflowDirect answers
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
It is most relevant to software development workflows. Confirm the original prerequisites before using it in production.
SkillSignal detected this source-specific command: npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/test-driven-development". Inspect the repository and command before running it.
The upstream source does not declare a dedicated Agent platform.
Static analysis detected exec-script signals. Review the cited source lines before installing; these signals are not a security audit.
This page combines upstream documentation with deterministic repository, quality, and static-risk signals. It is not described as a manual test or security review.
SkillSignal brief
Use when implementing a feature, fixing a bug, or refactoring — write a failing test first, then the code — even if the user just says 'add this function' or 'fix this bug'.
Useful in these contexts
Core capabilities
Distilled from the source
About 9 min · 15 sections
Adding a new function, method, or behavior
Fixing a bug (the bug needs a regression test before the fix)
Refactoring a unit whose current behavior is unclear
Any task where expected behavior can be expressed as an assertion
The failing test (file + test name) with captured failure output
The minimum-code diff that makes it pass
Captured green-run output
it('works') — no behavior described
One test covering "and/and/and" — split per behavior
Test that reaches into private state instead of testing observable behavior
Test that duplicates the production code's algorithm (tautology)
Quality breakdown
Based on traceable docs and repository signals; stars are not treated as quality.
Compare before choosing
These links are selected from shared tasks, functions, stacks, platforms, and same-name variants. Compare the source owner, documentation, permissions, and maintenance signals.
Use when implementing any feature or bugfix, before writing implementation code
Use when the user says "review the design", "check the UI", or wants a comprehensive UI/UX review. Uses a 7-phase methodology covering interaction, responsiveness, accessibility, and more.
Use when writing, generating, or improving Pest tests for Laravel — clear intent, good coverage, maintainable structure, and alignment with project testing conventions.
Test-driven development for Quarkus 3.x LTS using JUnit 5, Mockito, REST Assured, Camel testing, and JaCoCo. Use when adding features, fixing bugs, or refactoring event-driven services.
Expert-level Windows batch file (.bat/.cmd) skill for writing, debugging, and maintaining CMD scripts. Use when asked to "create a batch file", "write a .bat script", "automate a Windows task", "CMD scripting", "batch automation", "scheduled task script", "Windows shell script", or when working with .bat/.cmd files in the workspace. Covers cmd.exe syntax, environment variables, control flow, string processing, error handling, and integration with system tools.
Do NOT use when:
.md, AGENTS.md, README)agent-config package on skill/rule markdownPlain TDD (red → green → refactor) is the right size for most work. A small subset benefits from a gated 5-phase wrapper — Spec → Pseudocode → Architecture → Refine → Complete — where each gate produces a written artifact before the next phase runs.
Decision tree — escalate if any branch is true:
When escalating: drop the Spec artifact in agents/roadmaps/ (or the
project's planning location), capture it as an ADR via adr-create
when the decision is load-bearing, then run plain TDD inside each
Refine cycle. Do not skip RED→GREEN inside a SPARC phase — the
wrapper adds gates, not exemptions.
For everything else (single-AC ticket, leaf-module change, bug fix), stay on plain TDD — the section above.
1. Write ONE failing test that describes the desired behavior.
2. Run it. WATCH it fail for the right reason.
3. Write the MINIMUM production code to make it pass.
4. Run it again. Watch it pass.
5. Clean up (rename, deduplicate) while keeping the test green.
If step 2 is skipped, the test is not trusted — a test that has never failed proves nothing about the code under test.
WHEN UNTESTED CODE EXISTS AND A TEST IS NEEDED — DELETE THE CODE,
WRITE THE TEST, REIMPLEMENT. NEVER KEEP IT "AS REFERENCE".
Reading the existing implementation while writing its test is
test-after-the-fact with extra steps. The 12-row anti-rationalization
table that follows expands the most common ways this Iron Law gets
talked-around. Externalized to
testing-anti-patterns/process-anti-patterns.md
to keep this skill under the 400-line sunset trigger.
The flow runs as four modes. Each Forbidden item names how a reviewer checks it from the diff — an unverifiable prohibition does not ship.
| Mode | Goal | Activities | Forbidden (diff check) | Output contract |
|---|---|---|---|---|
| Design | One-sentence behavior + enumerated cases | Steps 1–2 | No production code (diff touches no src/** production path) · no test bodies yet | Case list (happy/boundary/error) |
| Test-Red | A failing test that fails RIGHT | Steps 3–4 | No production edits (diff = tests/** only) · test must fail at an assertion, not an import/setup error (failure output cites the assertion line) | Failing test + its observed failure reason |
| Implement | Minimum code to green | Steps 5–6 | No test edits (no tests/** paths in Implement-phase diffs — changing the assertion to fit the code is the canonical violation; genuinely-wrong test → STOP and ask, never silently edit) · no scope beyond the one case | Green run output |
| Debug | Fix a defect found later | (re-enter at 3) | No bugfix before a reproducing regression test exists (the fix commit contains a tests/** addition that fails without the fix) | Regression test + fix, verified red→green |
Step 0 of any resume: if agents/runtime/state/HANDOFF.md exists, resume
from its Mode + Contract-owed fields (see /agent-handoff file mode) instead
of re-deriving. Otherwise infer the mode from observable state — never
assume Design:
| Observed state | Resume in |
|---|---|
| No test for the target behavior | Design |
| Test exists, currently failing at an assertion | Implement |
| Test exists + passing, defect reported | Debug |
| Test failing at import/collection error | Test-Red (fix the test, not the code) |
At every mode transition, one consent-checkpoint sentence (per
ask-when-uncertain / autonomous-execution — no new mechanism): name the
mode you are leaving, the output contract you hand over, and the mode you
enter; under an autonomous mandate the sentence is stated, not asked.
State in one sentence: "When X happens, the system should do Y."
If you cannot state it in one sentence, the scope is too big — split into multiple tests, each covering one sentence.
Before the first test is written, run the
test-case-discovery funnel for the
behavior: dimension scan → case synthesis → optional subagent cross-check →
prioritization. Do not proceed to step 3 with fewer than the floor:
Each case from the list then gets its own RED → GREEN cycle (steps 3–6). A behavior whose only test is the happy path is not done — it is the first item of an unfinished case list.
Write the smallest test that expresses the sentence from step 1.
it_rejects_empty_email, not test_email_1.Execute the single test (targeted, not the full suite):
# PHP/Pest
./vendor/bin/pest --filter=it_rejects_empty_email
# JS/Vitest
npx vitest run --testNamePattern "rejects empty email"
Required observations before proceeding:
Add just enough production code to make the test green. No extra features, no unrelated refactoring, no "while I'm here" cleanups.
If you feel the urge to add a parameter, edge case, or helper not covered by the current test — stop. That belongs in the next RED step, not this GREEN step.
Re-run the same targeted command. Required:
With all tests green, you may:
Do not add new behavior during refactor — that needs its own failing test first. Re-run tests after the refactor to confirm still-green.
Back to step 1 with the next single-sentence behavior.
Twelve common rationalizations that fire before the test is written —
plus the delete-and-restart Iron Law — live in
testing-anti-patterns/process-anti-patterns.md.
Read the table when:
For mock-isolation failure modes (separate concern), see
testing-anti-patterns.
// tests/Unit/EmailValidatorTest.php — RED
it('rejects empty email', function () {
$result = (new EmailValidator())->validate('');
expect($result->isValid())->toBeFalse();
expect($result->error())->toBe('Email required');
});
Run: ./vendor/bin/pest --filter='rejects empty email' → fails
(EmailValidator does not exist yet, or returns isValid()=true).
// app/Validators/EmailValidator.php — GREEN (minimum)
final class EmailValidator
{
public function validate(string $email): EmailResult
{
if (trim($email) === '') {
return EmailResult::invalid('Email required');
}
return EmailResult::valid();
}
}
Run the filter again → passes. No additional rules (format, MX, length) until a next failing test drives them.
// src/retry.test.ts — RED
import { retry } from './retry';
it('retries a failing operation up to 3 times', async () => {
let attempts = 0;
const op = async () => {
attempts += 1;
if (attempts < 3) throw new Error('transient');
return 'ok';
};
await expect(retry(op)).resolves.toBe('ok');
expect(attempts).toBe(3);
});
Run: npx vitest run --testNamePattern "retries a failing" → fails
(retry is undefined).
// src/retry.ts — GREEN (minimum)
export async function retry<T>(op: () => Promise<T>): Promise<T> {
let lastError: unknown;
for (let i = 0; i < 3; i += 1) {
try { return await op(); } catch (e) { lastError = e; }
}
throw lastError;
}
Run again → passes. Configurable attempt count, backoff, and jitter all wait for their own failing tests.
expect() with three or four assertions on unrelated fields describes
multiple behaviors. Split them.it('works') — no behavior describedtest-case-discoveryquality-toolspest-testingtests-executesystematic-debuggingBefore marking TDD work complete:
See also developer-like-execution
for the broader think → analyze → verify loop this skill plugs into.