Test Driven Development
- 66 installs
- 1 repo stars
- Updated March 16, 2026
- pixel-process-ug/superkit-agents
Helps with testing & qa tasks.
About
test-driven-development is a Claude Code skill for testing & qa. It helps solo builders move faster with AI-assisted development.
- test-driven-development
- Testing & QA
- AI-coding skill
Test Driven Development by the numbers
- 66 all-time installs (skills.sh)
- +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,120 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pixel-process-ug/superkit-agents --skill test-driven-developmentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 66 |
|---|---|
| repo stars | ★ 1 |
| Last updated | March 16, 2026 |
| Repository | pixel-process-ug/superkit-agents ↗ |
What it does
Helps with testing & qa tasks.
Files
Test-Driven Development
Overview
TDD enforces the RED-GREEN-REFACTOR cycle as an unbreakable discipline: write a failing test, make it pass with minimal code, then clean up. This skill prevents untested production code from ever existing and ensures every line of implementation is driven by a verified requirement.
Announce at start: "I'm using the test-driven-development skill with the RED-GREEN-REFACTOR cycle."
---
Iron Law
┌─────────────────────────────────────────────────────────────────┐
│ HARD-GATE: NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST │
│ │
│ This is non-negotiable. There are no exceptions. If you are │
│ writing production code and there is no failing test demanding │
│ that code, you are violating this skill. STOP immediately │
│ and write the test first. │
└─────────────────────────────────────────────────────────────────┘---
Phase 1: RED (Write a Failing Test)
Goal: Write exactly ONE test that fails for the right reason.
Actions
1. Identify the smallest unit of behavior to implement next 2. Write a test that asserts that behavior exists 3. Run the test suite — confirm the new test FAILS 4. Read the failure message — confirm it fails for the RIGHT reason (missing functionality, not syntax error or import error) 5. If it fails for the wrong reason, fix the test until it fails correctly
STOP — HARD-GATE: Do NOT proceed to GREEN until:
- [ ] Test is written and saved
- [ ] Test suite has been run
- [ ] New test fails
- [ ] Failure reason is correct (tests the intended behavior)
---
Phase 2: GREEN (Make It Pass)
Goal: Write the MINIMUM production code to make the failing test pass.
Actions
1. Write only enough code to make the failing test pass 2. Do NOT refactor. Do NOT clean up. Do NOT optimize 3. Hardcode values if that makes the test pass — that is fine 4. Run the full test suite 5. ALL tests must pass (not just the new one)
STOP — HARD-GATE: Do NOT proceed to REFACTOR until:
- [ ] Production code is written
- [ ] Full test suite has been run
- [ ] ALL tests pass (new and existing)
- [ ] No more code was written than necessary
---
Phase 3: REFACTOR (Clean Up)
Goal: Improve code quality without changing behavior.
Actions
1. Look for duplication, poor naming, long methods, code smells 2. Make ONE refactoring change at a time 3. Run the full test suite after EACH change 4. If any test fails, undo the refactoring immediately 5. Continue until the code is clean
STOP — HARD-GATE: Do NOT proceed to next RED until:
- [ ] Code is clean and readable
- [ ] All tests still pass after refactoring
- [ ] No behavior was changed during refactoring
---
HARD-GATE Enforcement
┌─────────────────────────────────────────────────────────────┐
│ HARD-GATE: PHASE COMPLETION CHECK │
│ │
│ Before moving to next phase, ALL items in the │
│ STOP MARKER checklist must be satisfied. │
│ │
│ If ANY item is not satisfied: │
│ → STOP │
│ → Complete the missing item │
│ → Re-verify ALL items │
│ → ONLY THEN proceed │
└─────────────────────────────────────────────────────────────┘---
Watch Mode Discipline
After every change to any file (test or production), run the relevant test suite. No exceptions.
| Action | Run Tests? | Expected Result |
|---|---|---|
| Write a test | Yes | Failure (RED) |
| Write production code | Yes | Pass (GREEN) |
| Refactor code | Yes | Pass (still GREEN) |
| Any other edit | Yes | No regressions |
If your test runner supports watch mode, use it. If not, run tests manually after every save.
---
Decision Table: Test Type Selection
| Behavior Being Tested | Test Type | Framework Example |
|---|---|---|
| Pure function logic | Unit test | Vitest, pytest, cargo test |
| API endpoint request/response | Integration test | Supertest, httpx |
| Database query correctness | Integration test | Testcontainers |
| UI component rendering | Unit test | React Testing Library |
| Full user workflow | E2E test | Playwright |
| Error handling path | Unit test | Vitest, pytest |
---
Example Cycle
Requirement: "Users can register with email and password"
Behavior List:
1. Registration with valid email and password succeeds
2. Registration fails if email is empty
3. Registration fails if password is too short
4. Registration fails if email is already taken
Cycle 1 - Behavior 1:
RED: test_registration_with_valid_email_and_password_succeeds → FAIL (no register function)
GREEN: def register(email, password): return User(email=email) → PASS
REFACTOR: rename variable for clarity → PASS
Cycle 2 - Behavior 2:
RED: test_registration_fails_if_email_is_empty → FAIL (no validation)
GREEN: add if not email: raise ValueError → PASS
REFACTOR: extract validation to separate method → PASS
...continue for each behavior...---
Checklist: Starting a New Feature with TDD
1. [ ] Understand the requirement fully before writing any code 2. [ ] Break the requirement into a list of specific behaviors 3. [ ] Order behaviors from simplest to most complex 4. [ ] Create a task for the first behavior 5. [ ] Enter RED phase: write failing test for first behavior 6. [ ] Enter GREEN phase: write minimal code to pass 7. [ ] Enter REFACTOR phase: clean up 8. [ ] Create task for next behavior, repeat from step 5 9. [ ] After all behaviors are implemented, run full test suite 10. [ ] Invoke verification-before-completion before claiming done
---
Test Quality Standards
Each test must be:
| Standard | Definition |
|---|---|
| Fast | Milliseconds, not seconds |
| Isolated | No shared state between tests, no test ordering dependencies |
| Repeatable | Same result every time, no flakiness |
| Self-validating | Pass or fail, no manual interpretation needed |
| Timely | Written before the production code (that is the whole point) |
Each test should:
- Test ONE behavior or scenario
- Have a descriptive name that explains the scenario and expected outcome
- Follow Arrange-Act-Assert (or Given-When-Then) structure
- Use the minimum setup necessary
- Assert outcomes, not implementation details
---
Anti-Patterns / Common Mistakes
| Anti-Pattern | Why It Is Wrong | Correct Approach |
|---|---|---|
| Writing production code first | Defeats the purpose of TDD; tests shaped to pass | Write the test first, always |
| Writing multiple tests before any code | Batch testing defeats incremental design | One test, one cycle |
| Test passes on first run | Either test is wrong or behavior already exists | Investigate before proceeding |
| Spending >5 minutes in GREEN | Writing too much code at once | Simplify; make test more specific |
| Modifying tests to match code | Tests specify behavior; code must match tests | Fix the code, not the test |
| Skipping REFACTOR phase | Technical debt accumulates rapidly | Refactor every cycle |
| Not running tests after every change | Regressions go unnoticed | Run tests after every save |
---
Rationalization Prevention
| Excuse | Reality |
|---|---|
| "It's just a small change" | Small changes cause production outages. Test it. |
| "I'll write the tests after" | You will not. And if you do, they will be weaker because they were shaped to pass, not to specify. |
| "This is just a refactor" | Refactors change behavior more often than you think. The test suite proves they do not. |
| "I know this works" | You do not. You think you do. The test proves it. |
| "Tests would slow me down" | Debugging without tests slows you down 10x more. |
| "This code is too simple to test" | If it is too simple to test, it is too simple to get wrong — so the test will be trivial to write. Write it. |
| "I can't test this because of dependencies" | Then your design has a coupling problem. Fix the design. |
| "The test would be harder to write than the code" | That means you do not understand the requirements well enough. The test forces you to clarify. |
| "I'll just manually verify it" | Manual verification is not repeatable, not documented, and not trustworthy. |
| "This is throwaway/prototype code" | Prototype code has a habit of becoming production code. Test it now or regret it later. |
| "The framework makes it hard to test" | Use the framework's testing utilities, or isolate your logic from the framework. |
| "I'm under time pressure" | TDD is faster over any timeline longer than 20 minutes. The pressure is exactly why you need it. |
---
Red Flags
If you observe any of these, STOP and reassess:
| Red Flag | What It Means | Action |
|---|---|---|
| Writing production code with no failing test | Immediate violation | Stop. Write the test. |
| Test passes immediately on first run | Test is wrong or behavior exists | Investigate before proceeding |
| More than 5 minutes in GREEN phase | Writing too much code | Simplify. Make test more specific. |
| Refactoring changes behavior | Test coverage has a gap | Add missing tests |
| Tests modified to pass | Requirements inverted | Fix code to match tests |
| Multiple tests before any production code | Batch testing defeats purpose | One test at a time |
| Test suite not run after a change | Regressions invisible | Run tests. Always. Every time. |
---
Integration Points
| Skill | Relationship |
|---|---|
verification-before-completion | MUST be invoked before claiming any TDD work is complete |
systematic-debugging | When a test fails unexpectedly during REFACTOR, switch to debugging |
code-review | After completing a feature via TDD, review the test suite for completeness |
acceptance-testing | Acceptance criteria drive the behavior list for TDD cycles |
planning | Plan breaks features into behaviors suitable for TDD cycles |
testing-strategy | Strategy defines frameworks; TDD defines the cycle |
---
Test Types in TDD
| Type | Scope | Speed | When to Write |
|---|---|---|---|
| Unit (Primary) | Individual functions, methods, classes | Milliseconds | RED phase for every behavior |
| Integration (Secondary) | Component interactions | Seconds | After unit tests cover individual behaviors |
| E2E (Tertiary) | Complete user workflows | Seconds-minutes | Critical paths after unit and integration are solid |
---
Skill Type
RIGID — The RED-GREEN-REFACTOR cycle is mandatory and cannot be reordered, skipped, or combined. Every phase has a HARD-GATE that must be satisfied before proceeding. No production code without a failing test first.
Testing Anti-Patterns
Reference document for the test-driven-development skill. These are common patterns that undermine test quality, cause maintenance burden, and reduce confidence in the test suite.
---
1. Testing Implementation Details vs Behavior
The Problem: Tests that verify HOW something works rather than WHAT it does. These tests break whenever you refactor, even if behavior is unchanged.
Symptoms:
- Tests assert on internal method calls
- Tests check private state or internal data structures
- Tests verify the order of operations rather than the outcome
- Refactoring production code breaks tests even though behavior is identical
Examples of the anti-pattern:
# BAD: Testing implementation
def test_sort_uses_quicksort():
sorter = Sorter()
sorter.sort(data)
assert sorter._algorithm_used == "quicksort"
# GOOD: Testing behavior
def test_sort_returns_elements_in_ascending_order():
sorter = Sorter()
result = sorter.sort([3, 1, 2])
assert result == [1, 2, 3]Fix: Ask "If I changed the implementation but kept the same inputs and outputs, would this test still pass?" If no, you're testing implementation.
---
2. Excessive Mocking
The Problem: So many mocks that the test no longer verifies real behavior. The test passes but the real system could be broken.
Symptoms:
- More mock setup code than actual test code
- Mocking the thing you're supposed to be testing
- Mock returning mocks returning mocks (mock chains)
- Tests pass but integration fails
- Changing any interface breaks dozens of mocks
Rule of Thumb:
- Mock external services (APIs, databases, filesystems) at boundaries
- Do NOT mock the unit under test
- Do NOT mock value objects or simple data structures
- Prefer fakes (in-memory implementations) over mocks for complex dependencies
Fix: If your test has more than 3 mocks, your code probably has a design problem. Refactor to reduce coupling rather than adding more mocks.
---
3. Brittle Selectors
The Problem: Tests that depend on specific CSS selectors, DOM structure, XPaths, or other structural details that change frequently.
Symptoms:
- Tests break when UI layout changes but functionality is unchanged
- Selectors like
div > div:nth-child(3) > span.class-name - Tests break after CSS class renames
- Team avoids UI changes because tests will break
Fix:
- Use
data-testidattributes for test selectors - Use accessible selectors (role, label text) when possible
- Select by user-visible text or semantic meaning
- Avoid selecting by CSS class, tag nesting, or positional index
---
4. Test Interdependence
The Problem: Tests that depend on other tests running first, or that share mutable state.
Symptoms:
- Tests pass when run in order but fail when run individually
- Tests pass when run individually but fail when run together
- Test A sets up state that Test B relies on
- Shared database or file state between tests
- Test results change when tests run in parallel
Fix:
- Each test must set up its own state (Arrange phase)
- Each test must clean up after itself (or use per-test isolation)
- Use
beforeEach/setUpfor common setup, not shared test state - Run tests in random order to catch hidden dependencies
- Never rely on test execution order
---
5. Slow Test Suites
The Problem: Test suite takes so long that developers stop running it, or only run it in CI where feedback is delayed.
Symptoms:
- Test suite takes more than 30 seconds for unit tests
- Developers skip running tests locally
- "I'll let CI catch it" mentality
- Real network calls, file I/O, or database operations in unit tests
- Sleep/wait calls in tests
Causes and fixes:
| Cause | Fix |
|---|---|
| Real database calls | Use in-memory database or repository fakes |
| Real network calls | Mock HTTP clients at the boundary |
| Sleep statements | Use event-based waiting or mock timers |
| Expensive setup | Lazy initialization, share immutable fixtures |
| Too many integration tests | Convert to unit tests where possible |
| Large test data | Use minimal data sets, builder patterns |
Target: Unit test suite should complete in under 10 seconds. Integration tests under 60 seconds.
---
6. Snapshot Overuse
The Problem: Using snapshot tests as a lazy substitute for specific assertions. Snapshots capture everything, making it unclear what behavior matters.
Symptoms:
- Snapshot files with hundreds or thousands of lines
- Developers update snapshots without reviewing changes
--update-snapshotsrun reflexively when tests fail- No one knows what the snapshot is actually testing
- Snapshot diffs are noise, not signal
When snapshots ARE appropriate:
- Serialization formats (JSON API responses, GraphQL schemas)
- Generated output that is complex but must remain stable
- Visual regression testing (with proper review tooling)
When snapshots are NOT appropriate:
- Testing business logic
- Testing individual component behavior
- Testing anything where you can write a specific assertion
Fix: For each snapshot test, ask: "What specific behavior would break if this snapshot changed?" Write a targeted assertion for that behavior instead.
---
7. Testing Third-Party Code
The Problem: Writing tests that verify your dependency works correctly. That's the dependency's job, not yours.
Symptoms:
- Tests for standard library functions
- Tests that verify ORM query behavior
- Tests that check if HTTP client sends requests correctly
- Tests that validate framework routing works
What to test instead:
- Test YOUR code that USES the dependency
- Test your wrappers and adapters
- Test your error handling when the dependency fails
- Test your configuration of the dependency
Example:
# BAD: Testing that the HTTP library works
def test_requests_library_sends_get():
response = requests.get("https://example.com")
assert response.status_code == 200
# GOOD: Testing your code that uses the HTTP library
def test_user_service_returns_user_on_success():
http_client = FakeHttpClient(response={"id": 1, "name": "Alice"})
service = UserService(http_client)
user = service.get_user(1)
assert user.name == "Alice"---
8. God Tests (Testing Too Much in One Test)
The Problem: A single test that verifies multiple behaviors, making it unclear what failed and why.
Symptoms:
- Test name includes "and" (e.g.,
test_create_user_and_send_email_and_update_log) - More than 3 assertions per test (unless asserting properties of a single result)
- Test has multiple Act phases
- Test failure message doesn't tell you what's actually wrong
- Tests longer than 20 lines of code
Fix:
- One behavior per test
- One Act (action) per test
- Name tests after the specific scenario being verified
- Split God tests into multiple focused tests
Example:
# BAD: God test
def test_user_registration():
user = register("alice@test.com", "password123")
assert user.email == "alice@test.com" # behavior 1
assert user.is_active == False # behavior 2
assert email_sent_to("alice@test.com") # behavior 3
assert audit_log_contains("registration") # behavior 4
assert user.created_at is not None # behavior 5
# GOOD: Focused tests
def test_registration_creates_user_with_email(): ...
def test_registration_creates_inactive_user(): ...
def test_registration_sends_confirmation_email(): ...
def test_registration_creates_audit_log_entry(): ...
def test_registration_sets_creation_timestamp(): ...---
9. Missing Edge Cases
The Problem: Tests only cover the happy path, leaving boundary conditions, error states, and unusual inputs untested.
Common missed edge cases:
| Category | Examples |
|---|---|
| Boundary values | 0, -1, MAX_INT, empty string, single character |
| Empty collections | Empty list, empty map, null/None |
| Null/undefined | Null inputs, missing optional fields |
| Concurrency | Simultaneous access, race conditions |
| Error states | Network failure, disk full, permission denied |
| Unicode | Emoji, RTL text, special characters, multi-byte |
| Time zones | DST transitions, UTC vs local, date boundaries |
| Large inputs | Very long strings, very large numbers, many items |
| Duplicate data | Same item twice, duplicate keys |
| Ordering | Already sorted, reverse sorted, single element |
Fix: For each function, systematically consider: 1. What happens with empty/null input? 2. What happens at boundary values? 3. What happens when an external call fails? 4. What happens with malformed input? 5. What happens under concurrent access?
---
10. Flaky Tests (Time-Dependent, Race Conditions)
The Problem: Tests that sometimes pass and sometimes fail without any code changes. These destroy trust in the test suite.
Common causes:
Time-Dependent Tests
# BAD: Depends on wall clock
def test_token_not_expired():
token = create_token(expires_in=1)
assert token.is_valid() # Might fail if machine is slow
# GOOD: Control time
def test_token_not_expired():
clock = FakeClock(now=datetime(2025, 1, 1))
token = create_token(expires_in=3600, clock=clock)
clock.advance(seconds=3599)
assert token.is_valid()Race Conditions
# BAD: Relies on timing
def test_async_operation():
start_background_job()
time.sleep(2) # Hope it's done by now
assert job_completed()
# GOOD: Wait for completion signal
def test_async_operation():
job = start_background_job()
job.wait(timeout=10)
assert job.completedRandom Data Without Seeds
# BAD: Non-deterministic
def test_random_selection():
result = pick_random(items)
assert result in items # Always passes, tests nothing
# GOOD: Seed the randomness
def test_random_selection_with_seed():
result = pick_random(items, seed=42)
assert result == items[3] # Deterministic, verifiableFix checklist for flaky tests: 1. Control time with fake clocks 2. Control randomness with seeds 3. Use deterministic waits (signals, not sleeps) 4. Isolate filesystem and network access 5. Avoid shared mutable state 6. Run the test 100 times in a loop to confirm it's stable
---
Summary: Quick Reference
| Anti-Pattern | One-Line Fix |
|---|---|
| Implementation testing | Assert outcomes, not internals |
| Excessive mocking | Reduce coupling, use fakes |
| Brittle selectors | Use data-testid or accessible selectors |
| Test interdependence | Each test owns its own state |
| Slow suites | Mock I/O, minimize data, no sleeps |
| Snapshot overuse | Write specific assertions |
| Testing third-party code | Test your code, not theirs |
| God tests | One behavior per test |
| Missing edge cases | Systematically check boundaries |
| Flaky tests | Control time, randomness, concurrency |