tdd-implementation
# TDD Implementation Workflow
What this skill does
# TDD Implementation Workflow
> **See also:** [tdd.md](../../concepts/tdd.md) for TDD philosophy and when to use TDD vs standard implementation.
Use Test-Driven Development for features that benefit from upfront behavior specification.
**Invoke for:**
- Adding features with testable inputs/outputs
- Fixing bugs (test captures the bug first)
- Implementing validation, parsing, or transformation logic
- Building state machines or workflows
**Skip TDD for:**
- UI layout and styling
- Configuration changes
- Glue code with no logic
- Exploratory prototyping
---
## TDD State Machine
```
╭─ TDD STATE MACHINE ───────────────────────────────────────────────────────────────╮
[START] ──► [RED] ──► [GREEN] ──► [REFACTOR] ──► [VERIFY] ──► [COMPLETE]
│ ▲ │ │ │
▼ │ ▼ ▼ ▼
Write │ Write impl Clean up Run ORIGINAL
test │ Run test Run tests use-case!
MUST │ MUST PASS MUST PASS │
FAIL │ │
│ ┌───────────┴───────────┐
│ ▼ ▼
│ STILL FAILS? WORKS!
│ │ │
└────────────────────┘ ▼
Test didn't capture [COMPLETE]
the REAL bug - write
NEW test that fails
for same reason as
original use-case
╰───────────────────────────────────────────────────────────────────────────────────╯
```
**Release transitions are VERIFIED by actually running tests.**
---
## STEP 1: RED RELEASE - Write Failing Test
### Actions:
1. Create test file following project conventions
2. **If changing behavior**: Find and UPDATE existing test, don't create duplicate
3. Write test that defines expected behavior
4. Run the test - it **MUST fail**
### Run Test Command (adapt to your stack):
```bash
# JavaScript/TypeScript
npm test -- --grep "your test name"
# Python
pytest tests/test_file.py::test_function -v
# Go
go test -run TestFunctionName ./...
# Rust
cargo test test_name
```
### Verify Test FAILS:
- Look for failure output confirming test ran and failed
- If test **passes**: feature may already exist or test is wrong - investigate
### Commit:
```bash
git add tests/
git commit -m "test: add failing test for [feature]
- Describes expected behavior
- Will pass when feature is implemented"
```
---
## ⚠️ CHANGING EXISTING BEHAVIOR vs NEW FEATURES
**CRITICAL: Update existing tests when changing behavior (avoid duplicates).**
### Adding NEW Feature:
- Create a NEW test method
- Test should FAIL because feature doesn't exist
- Implement feature → test passes
### Changing EXISTING Behavior (Bug Fix / Behavior Change):
- **UPDATE** the existing test to reflect the NEW expected behavior, OR
- **DELETE** the old test and create a new one
**WRONG approach (creates conflicts):**
```
// Old test expects behavior A
testDoesA() { ... expects A ... }
// New test expects behavior B
testDoesB() { ... expects B ... }
// ❌ Now you have TWO conflicting tests!
```
**CORRECT approach:**
```
// Update the existing test to reflect new behavior
testBehavior() {
... expects B (the NEW correct behavior) ...
}
// ✓ One test, one source of truth
```
---
## STEP 2: GREEN RELEASE - Implement Code
### Actions:
1. NOW you can edit production code
2. Write **minimal** code to make test pass
3. No cleverness, no optimization - just make it work
4. Run the test - it **MUST pass**
### Verify Test PASSES:
- All tests pass including your new one
- No regressions in existing tests
### Commit:
```bash
git add src/
git commit -m "feature: implement [feature]
- Makes failing test pass
- [Brief description of implementation approach]"
```
---
## STEP 3: REFACTOR RELEASE - Clean Up
### Actions:
1. Clean up implementation if obvious improvements exist
2. Remove any debug code
3. Run **full test suite** to check for regressions
4. Tests **MUST still pass**
### Only commit if changes made:
```bash
git add .
git commit -m "refactor: clean up [feature]
- [What was improved]
- No behavior changes"
```
---
## STEP 4: VERIFY AGAINST ORIGINAL USE-CASE
**⚠️ CRITICAL: Test passing ≠ bug is fixed. Verify your RED test captured the actual bug.**
### Verification Steps:
1. **Return to the original scenario** - The exact inputs/conditions that exposed the bug
2. **Run the original use-case** - Not your new test, but the ORIGINAL failing scenario
3. **Confirm it now works** - The specific behavior that was broken is now correct
4. **Check for side effects** - The fix didn't break related functionality
### Why This Matters:
- Your RED test is a *hypothesis* about what the bug is
- The test might pass while the original bug remains (tested wrong thing)
- Simplified test cases may miss edge cases in the real scenario
- Only the original use-case proves the bug is truly fixed
### If Original Use-Case Still Fails:
**Your RED test wasn't capturing the ACTUAL bug. Return to RED release:**
1. **Analyze why the fix didn't work**:
- The test passed but the bug persists → test was testing the wrong thing
- The test was an approximation, not a faithful reproduction
- You fixed a symptom, not the root cause
2. **Write a NEW test** that:
- Fails for the SAME reason as the original use-case
- Uses the exact inputs/conditions that exposed the bug
- Is a faithful reproduction, not an approximation
3. **Repeat the full cycle**: RED → GREEN → REFACTOR → VERIFY
**This loop continues until the ORIGINAL use-case works.**
---
## TDD Commit Pattern
TDD produces 2-3 atomic commits per feature:
```
test: add failing test for email validation
- Tests valid email formats accepted
- Tests invalid formats rejected
- Tests empty input handling
feature: implement email validation
- Regex pattern validates format
- Returns boolean for validity
- Handles edge cases
refactor: extract validation helper (optional)
- Moved pattern to constant
- No behavior changes
```
---
## Quick Reference: Decision Heuristic
**Can you write `expect(fn(input)).toBe(output)` before writing `fn`?**
→ **Yes**: Use this TDD workflow
→ **No**: Standard implementation, add tests after if needed
---
## Good Tests vs Bad Tests
### Test behavior, not implementation:
- ✅ Good: "returns formatted date string"
- ❌ Bad: "calls formatDate helper with correct params"
### One concept per test:
- ✅ Good: Separate tests for valid input, empty input, malformed input
- ❌ Bad: Single test checking all edge cases
### Descriptive names:
- ✅ Good: "should reject empty email", "returns null for invalid ID"
- ❌ Bad: "test1", "handles error", "works correctly"
### No implementation details:
- ✅ Good: Test public API, observable behavior
- ❌ Bad: Mock internals, test private methods
---
## Related Skills
- `build-test-report` - Run tests and report results
- `git-commit` - Commit conventions
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.