PramodDutta/qaskills/seed-skills/tdd-patterns/SKILL.md
TDD Patterns
Practice strict red-green-refactor test-driven development — write one failing test first, make it pass with the minimum code, then refactor under green, with worked cycles in Jest and pytest, AAA structure, and behavior-based test naming.
- Source repository stars
- 195
- Declared platforms
- 4
- Static risk flags
- 1
- Last source update
- 2026-08-04
- Source checked
- 2026-08-04
Decision brief
What it does—and where it fits
This skill makes an AI agent develop features test-first: write exactly one failing test, watch it fail for the right reason, write the minimum production code to pass, then refactor while green. It enforces the discipline most "TDD" sessions skip — never writing production code…
Not for
- Writing the implementation first, then backfilling tests. That is test-after; you lose the design pressure and the verified-red guarantee. The tests will mirror the code's bugs.
- A batch of failing tests before any implementation. You committed to a design before feedback. One red at a time.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Declared | Source record | Install path and trigger |
| Claude Code | Declared | Source record | Install path and trigger |
| Cursor | Declared | Source record | Install path and trigger |
| Gemini CLI | Declared | Source record | Install path and trigger |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/PramodDutta/qaskills --skill "seed-skills/tdd-patterns"Inspect the Agent Skill "TDD Patterns" from https://github.com/PramodDutta/qaskills/blob/c924c5f7fee5fa410f267031061e492eb051757a/seed-skills/tdd-patterns/SKILL.md at commit c924c5f7fee5fa410f267031061e492eb051757a. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Workflow: One Full Cycle in Jest (TypeScript)
Feature: a PriceCalculator that applies tiered bulk discounts.
Feature: a PriceCalculator that applies tiered bulk discounts.RED — write the smallest failing test:bash npx jest price-calculator - 02
Workflow: Same Discipline in pytest
Feature: a password strength validator, driven boundary-first.
Feature: a password strength validator, driven boundary-first. - 03
Core Principles
1. One failing test at a time. Not a suite of ten pending tests — one. Multiple red tests mean you are designing in your head instead of letting tests drive. 2. Watch the test fail before making it pass. A test you never saw red might be passing vacuously (wrong assertion, testi…
One failing test at a time. Not a suite of ten pending tests — one. Multiple red tests mean you are designing in your head instead of letting tests drive.Watch the test fail before making it pass. A test you never saw red might be passing vacuously (wrong assertion, testing the mock, typo'd import). The red step verifies the test itself.Write the minimum code that passes — even if it is embarrassingly dumb. Returning a hardcoded value is legal; the next test forces the generalization. "Fake it till the tests make you make it." - 04
FAIL — Cannot find module './price-calculator' <- failing for the RIGHT reason
typescript // src/price-calculator.ts export function calculateTotal(unitPrice: number, quantity: number): number { return unitPrice quantity; } typescript it('applies a 10 percent discount at 10 units or more', () = { expect(calculateTotal(4.0, 10)).toBe(36.0); // 40 - 10% });
typescript // src/price-calculator.ts export function calculateTotal(unitPrice: number, quantity: number): number { return unitPrice quantity; } typescript it('applies a 10 percent discount at 10 units or more', () = {…it('applies a 20 percent discount at 50 units or more', () = { expect(calculateTotal(2.0, 50)).toBe(80.0); // 100 - 20% }); typescript export function calculateTotal(unitPrice: number, quantity: number): number { const…export function calculateTotal(unitPrice: number, quantity: number): number { const tier = DISCOUNTTIERS.find((t) = quantity = t.minQty)!; return unitPrice quantity tier.multiplier; } python - 05
tests/testpasswordpolicy.py
from app.passwordpolicy import validate
from app.passwordpolicy import validateclass TestValidate: def testrejectspasswordsshorterthan12chars(self): Arrange / Act result = validate("Short1!aaaa") 11 charsAssert assert result.ok is False assert "at least 12 characters" in result.errors
Permission review
Static risk signals and limitations
Runs scripts
The documentation asks the agent to run terminal commands or scripts.
npx jest price-calculatorEvidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 89/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 195 | Source | Repository attention, not individual Skill quality |
| Compatibility | 4 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- PramodDutta/qaskills
- Skill path
- seed-skills/tdd-patterns/SKILL.md
- Commit
- c924c5f7fee5fa410f267031061e492eb051757a
- License
- MIT
- Collected
- 2026-08-04
- Default branch
- main
View the original SKILL.md
TDD Patterns
This skill makes an AI agent develop features test-first: write exactly one failing test, watch it fail for the right reason, write the minimum production code to pass, then refactor while green. It enforces the discipline most "TDD" sessions skip — never writing production code without a failing test demanding it. Trigger it when the user asks for TDD, test-first development, or when implementing new logic in a codebase that already has a test runner wired up.
Core Principles
- One failing test at a time. Not a suite of ten pending tests — one. Multiple red tests mean you are designing in your head instead of letting tests drive.
- Watch the test fail before making it pass. A test you never saw red might be passing vacuously (wrong assertion, testing the mock, typo'd import). The red step verifies the test itself.
- Write the minimum code that passes — even if it is embarrassingly dumb. Returning a hardcoded value is legal; the next test forces the generalization. "Fake it till the tests make you make it."
- Refactor only on green, and refactor both sides. Production code and test code rot equally. Duplication in tests is a design smell exactly as it is in
src/. - Test behavior through the public API, never internals. If renaming a private method breaks tests, the tests are coupled to implementation and will resist every refactor instead of enabling it.
- Name tests as behavioral sentences.
rejects expired coupons at the boundary minutetells the next reader the rule;test_coupon_3tells them nothing. - The cycle is minutes, not hours. If you have been red for 20 minutes, the step was too big — delete, take a smaller bite.
Workflow: One Full Cycle in Jest (TypeScript)
Feature: a PriceCalculator that applies tiered bulk discounts.
RED — write the smallest failing test:
// src/price-calculator.test.ts
import { describe, expect, it } from '@jest/globals';
import { calculateTotal } from './price-calculator';
describe('calculateTotal', () => {
it('returns unit price times quantity with no discount under 10 units', () => {
// Arrange
const unitPrice = 4.0;
const quantity = 3;
// Act
const total = calculateTotal(unitPrice, quantity);
// Assert
expect(total).toBe(12.0);
});
});
npx jest price-calculator
# FAIL — Cannot find module './price-calculator' <- failing for the RIGHT reason
GREEN — minimum code, no speculation:
// src/price-calculator.ts
export function calculateTotal(unitPrice: number, quantity: number): number {
return unitPrice * quantity;
}
RED again — the next test forces the discount rule:
it('applies a 10 percent discount at 10 units or more', () => {
expect(calculateTotal(4.0, 10)).toBe(36.0); // 40 - 10%
});
it('applies a 20 percent discount at 50 units or more', () => {
expect(calculateTotal(2.0, 50)).toBe(80.0); // 100 - 20%
});
GREEN:
export function calculateTotal(unitPrice: number, quantity: number): number {
const subtotal = unitPrice * quantity;
if (quantity >= 50) return subtotal * 0.8;
if (quantity >= 10) return subtotal * 0.9;
return subtotal;
}
REFACTOR — under green, extract the tier table:
const DISCOUNT_TIERS: ReadonlyArray<{ minQty: number; multiplier: number }> = [
{ minQty: 50, multiplier: 0.8 },
{ minQty: 10, multiplier: 0.9 },
{ minQty: 0, multiplier: 1.0 },
];
export function calculateTotal(unitPrice: number, quantity: number): number {
const tier = DISCOUNT_TIERS.find((t) => quantity >= t.minQty)!;
return unitPrice * quantity * tier.multiplier;
}
Run the suite after the refactor. Still green, behavior unchanged, structure improved. That is one complete cycle.
Workflow: Same Discipline in pytest
Feature: a password strength validator, driven boundary-first.
# tests/test_password_policy.py
import pytest
from app.password_policy import validate
class TestValidate:
def test_rejects_passwords_shorter_than_12_chars(self):
# Arrange / Act
result = validate("Short1!aaaa") # 11 chars
# Assert
assert result.ok is False
assert "at least 12 characters" in result.errors
def test_accepts_a_12_char_password_meeting_all_rules(self):
result = validate("Sturdy-Pass1") # exactly 12
assert result.ok is True
assert result.errors == []
pytest tests/test_password_policy.py -x
# ModuleNotFoundError: No module named 'app.password_policy' <- correct red
Minimum green:
# app/password_policy.py
from dataclasses import dataclass, field
@dataclass
class Result:
ok: bool
errors: list[str] = field(default_factory=list)
def validate(password: str) -> Result:
if len(password) < 12:
return Result(ok=False, errors=["at least 12 characters"])
return Result(ok=True)
Next red drives the remaining rules — and parametrize keeps each rule one logical test:
@pytest.mark.parametrize(
("password", "missing"),
[
("alllowercase-12", "an uppercase letter"),
("ALLUPPERCASE-12", "a lowercase letter"),
("NoDigitsHere-Ab", "a digit"),
],
)
def test_reports_each_missing_character_class(self, password, missing):
result = validate(password)
assert result.ok is False
assert missing in result.errors
Green, then refactor the rule checks into a table of (predicate, message) pairs — same move as the discount tiers above.
Patterns
Triangulation
When one example lets you fake it (return 36.0), add a second example with different inputs. Two data points force the general implementation; that is exactly when to generalize, not before.
Arrange-Act-Assert, enforced by whitespace
Every test reads as three blocks separated by blank lines. One Act per test. If you need a second Act, you need a second test.
Test list as a scratchpad
Before starting, jot the behaviors as comments; convert one at a time into a real failing test:
// TODO test list — price-calculator
// [x] no discount under 10 units
// [x] 10% at 10+
// [x] 20% at 50+
// [ ] rejects negative quantity with RangeError
// [ ] rounds to 2 decimal places (0.1 + 0.2 money bugs)
Boundary-first ordering
Write the boundary test (exactly 10 units, exactly 12 chars) before the comfortable middle. Off-by-one bugs live at boundaries; TDD that skips them certifies nothing.
Best Practices
- Run only the focused test file during the cycle (
jest price-calculator --watch,pytest -x -k password); run the full suite before commit. - Commit on every green —
git commitafter each cycle gives you a bisectable history and a free undo for failed refactors. - When a bug report arrives, write the failing test that reproduces it before touching the fix. The bug becomes a permanent regression guard.
- Keep unit tests free of I/O. If a test needs the network or filesystem, it is an integration test; move it and mock the port in unit tests.
- Treat a hard-to-write test as design feedback: too many mocks means too many dependencies; a huge Arrange block means the unit does too much.
Anti-Patterns
- Writing the implementation first, then backfilling tests. That is test-after; you lose the design pressure and the verified-red guarantee. The tests will mirror the code's bugs.
- A batch of failing tests before any implementation. You committed to a design before feedback. One red at a time.
- Skipping the refactor step for weeks. Red-green-red-green without refactoring produces working spaghetti; the third step is where design happens.
- Asserting on mocks of your own code (
expect(repo.save).toHaveBeenCalled()as the only assertion). Verify observable outcomes; interaction-only tests pass while behavior is broken. - 100%-coverage worship. Coverage is a byproduct of TDD, not a goal. Chasing the last 4% on getters produces brittle, valueless tests.
- Changing the test and the code in the same step when something fails. Change one side, rerun, then the other — otherwise you cannot tell which change fixed (or masked) the failure.
When to Trigger This Skill
- The user says TDD, test-first, red-green-refactor, or "write the test before the code".
- Implementing a new pure-logic module (pricing, validation, parsing, date math) where fast unit cycles shine.
- A bug fix is requested — drive it with a reproducing failing test first.
- The user wants to learn or enforce AAA structure and behavioral test naming in Jest or pytest.
- A code review reveals tests coupled to internals or written after the fact, and the team wants to reverse the habit.
Alternatives
Compare before choosing
alirezarezvani/claude-skills
chaos-engineering
Use when planning, running, or learning from chaos engineering experiments. Triggers on "chaos experiment", "fault injection", "gameday", "resilience test", "blast radius", "steady state", "abort criteria", "Chaos Toolkit", "Chaos Mesh", "Litmus", "Gremlin", "AWS FIS", or any deliberate failure-injection question. Ships experiment designer, blast-radius calculator, and postmortem generator (all stdlib Python), 4 references on chaos principles + experiment design + attack taxonomy + tooling lands
PramodDutta/qaskills
Robot Framework Testing
Expert-level Robot Framework testing skill covering keyword-driven syntax, SeleniumLibrary, RequestsLibrary, custom Python keywords, data-driven testing, resource files, and parallel execution with Pabot.
PramodDutta/qaskills
Angry User Simulator
Simulate aggressive user behavior patterns including rapid clicking, random navigation, form abuse, tab spamming, and unexpected interaction sequences to find UI resilience issues
PramodDutta/qaskills
Loading State Tester
Verify loading indicators, skeleton screens, and progress bars appear correctly during async operations and disappear on completion or error.