eXtreme Programming Test-Driven Development (XP-style TDD) Skill. This skill provides both reference documentation AND execution capabilities for the full PLAN -> RED -> GREEN -> REFACTOR workflow.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill enables test-driven development (TDD) using the Red-Green-Refactor cycle. It supports comprehensive language coverage (Rust, Python, TypeScript, Go, Java, C#, C++) with language-specific test runners, conventions, and best practices.
[<start>Start] -> [Phase 1: PLAN]
[Phase 1: PLAN|
Design test architecture
Identify edge cases
Map requirements to tests
] -> [Phase 2: RED]
[Phase 2: RED|
Write failing test
Verify test fails meaningfully
] -> [Phase 3: GREEN]
[Phase 3: GREEN|
Implement minimal code
Make test pass
] -> [Phase 4: REFACTOR]
[Phase 4: REFACTOR|
Clean up code
Maintain green tests
] -> [More Features?]
[More Features?] yes -> [Phase 2: RED]
[More Features?] no -> [<end>Complete]
Understand Requirements
Artifact Detection (Conditional)
fd -g '*test*' -g '*spec*' -e ts -e py -e rs -e java -e go $ARGUMENTS
test -f package.json && rg '"vitest"|"jest"|"mocha"' package.json
test -f Cargo.toml && rg 'proptest|quickcheck' Cargo.toml
Design Test Architecture
Prepare Run Phase
.outline/tests/ or language-specific locationUse sequential-thinking for:
- Planning Red-Green-Refactor cycles
- Test case prioritization
- Dependency ordering
Use actor-critic-thinking for:
- Evaluating test coverage
- Challenging test effectiveness
- Edge case identification
Use shannon-thinking for:
- Coverage gap analysis
- Flaky test risk assessment
- Property-based test candidates
// Target: .outline/tests/{module}_test.{ext}
// ============================================
// From requirement: {requirement text}
// ============================================
// Unit Test: {description}
// Arrange: {setup description}
// Act: {action description}
// Assert: {expected outcome}
test_case_1() {
// RED: This test should fail initially
// GREEN: Minimal implementation to pass
// REFACTOR: Improve without breaking
}
// Property-Based Test: {invariant description}
// For all valid inputs, {property} should hold
property_test_1() {
// Generator: {input generation strategy}
// Property: {invariant to verify}
}
// Edge Case: {boundary condition}
edge_case_1() {
// Boundary: {specific edge case}
// Expected: {behavior at boundary}
}
# Create .outline/tests directory structure
mkdir -p .outline/tests/{unit,integration,property}
# TypeScript/JavaScript
npx vitest run || echo "RED: Tests failing as expected"
# Python
pytest .outline/tests/ -v || echo "RED: Tests failing as expected"
# Rust
cargo test || echo "RED: Tests failing as expected"
# Go
go test ./... || echo "RED: Tests failing as expected"
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_cart_has_zero_total() {
let cart = ShoppingCart::new();
assert_eq!(0, cart.total());
}
#[test]
fn test_adding_item_increases_total() {
let mut cart = ShoppingCart::new();
cart.add_item(Item::new("Widget", 10));
assert_eq!(10, cart.total());
}
#[test]
fn test_quantity_multiplies_price() {
let mut cart = ShoppingCart::new();
cart.add_item(Item::new("Widget", 10).quantity(3));
assert_eq!(30, cart.total());
}
}
Run: cargo test -> FAILS (ShoppingCart doesn't exist)
pub struct Item {
name: String,
price: i32,
quantity: i32,
}
impl Item {
pub fn new(name: &str, price: i32) -> Self {
Self { name: name.to_string(), price, quantity: 1 }
}
pub fn quantity(mut self, qty: i32) -> Self {
self.quantity = qty;
self
}
}
pub struct ShoppingCart {
items: Vec<Item>,
}
impl ShoppingCart {
pub fn new() -> Self { Self { items: Vec::new() } }
pub fn add_item(&mut self, item: Item) { self.items.push(item); }
pub fn total(&self) -> i32 {
self.items.iter().map(|item| item.price * item.quantity).sum()
}
}
# TypeScript/JavaScript
npx vitest run || exit 13
# Python
pytest .outline/tests/ -v || exit 13
# Rust
cargo test || exit 13
# Go
go test ./... || exit 13
#[derive(Debug, Clone)]
pub struct Item {
name: String,
price: i32,
quantity: i32,
}
impl Item {
pub fn new(name: impl Into<String>, price: i32) -> Self {
Self { name: name.into(), price, quantity: 1 }
}
pub fn with_quantity(mut self, qty: i32) -> Self {
self.quantity = qty;
self
}
pub fn subtotal(&self) -> i32 { self.price * self.quantity }
}
#[derive(Debug, Default)]
pub struct ShoppingCart { items: Vec<Item> }
impl ShoppingCart {
pub fn new() -> Self { Self::default() }
pub fn add_item(&mut self, item: Item) { self.items.push(item); }
pub fn total(&self) -> i32 { self.items.iter().map(Item::subtotal).sum() }
pub fn item_count(&self) -> usize { self.items.len() }
}
# TypeScript/JavaScript
npx vitest run --coverage || exit 13
# Python
pytest --cov=$MODULE --cov-report=html || exit 14
# Rust
cargo tarpaulin --out Html || exit 14
# Go
go test -coverprofile=coverage.out ./... || exit 14
| Code | Meaning | Action |
|---|---|---|
| 0 | All tests pass, coverage met | Continue with next feature |
| 11 | Framework missing | Install test framework |
| 12 | No test files | Run plan phase, create tests |
| 13 | Tests failed | Fix implementation or test |
| 14 | Coverage low | Add more tests |
| 15 | Refactoring broke tests | Revert changes, refactor carefully |
| Language | Test Framework | Command | Watch Mode |
|---|---|---|---|
| Rust | cargo test | cargo test | cargo watch -x test |
| Python | pytest | pytest | pytest-watch |
| TypeScript | vitest/jest | vitest run | vitest --watch |
| Go | go test | go test ./... | gotestsum --watch |
| Java | JUnit 5 | mvn test | IDE integration |
| C# | xUnit | dotnet test | dotnet watch test |
| C++ | GoogleTest | ctest | fd *.cpp | entr ctest |
| Language | Unit Test | Property Test | Mock |
|---|---|---|---|
| Rust | cargo test | proptest | mockall |
| Python | pytest | hypothesis | pytest-mock |
| TypeScript | vitest | fast-check | vi.mock |
| Go | go test | gopter | gomock |
| Java | JUnit 5 | jqwik | Mockito |
| C# | xUnit | FsCheck | Moq |
| C++ | GoogleTest | rapidcheck | GMock |
cargo test # Rust
pytest # Python
vitest run # TypeScript
go test ./... # Go
mvn test # Java
dotnet test # C#
ctest # C++
cargo test test_name -- --show-output
pytest --cov=module --cov-report=term
vitest --coverage --watch
go test -v -cover ./...
mvn test -Dtest=TestClass#method
dotnet test --collect:"XPlat Code Coverage"
ctest --verbose --output-on-failure
cargo watch -x 'tarpaulin --out Lcov --all-features'
pytest-watch -v -m "not slow" -n auto
vitest --ui --typecheck --browser.enabled=true
gotestsum --watch -- -race -bench=. ./...
mvn verify pitest:mutationCoverage
dotnet watch test --logger "console;verbosity=detailed"
ctest --repeat until-fail:10 --parallel 4
Rust: test_<feature>_<condition>_<expected>
Python: test_<feature>_when_<condition>_then_<expected>
TypeScript: 'should <expected> when <condition>'
Go: Test<Feature><Condition>
Java: @DisplayName("Should <expected> when <condition>")
C#: Should<Expected>When<Condition>
C++: TEST(Suite, Should<Expected>When<Condition>)
def test_discount_applies_to_total():
# ARRANGE
cart = ShoppingCart()
cart.add_item(Item("Widget", 100))
discount = Discount(percent=10)
# ACT
total = cart.calculate_total(discount)
# ASSERT
assert total == 90
| Symptom | Cause | Resolution |
|---|---|---|
| Exit 11 | Test framework missing | Install: npm i -D vitest, pip install pytest, cargo add --dev proptest |
| Exit 12 | No test files | Run plan phase first |
| Exit 13 | Tests failed | Debug specific test |
| Exit 14 | Coverage too low | Add tests for uncovered paths |
| Flaky test | Non-determinism | Fix time/random/network dependencies |
| Slow tests | Too much I/O or sleep | Use mocks, reduce wait times |
| Test passes alone, fails in suite | Shared state pollution | Isolate test fixtures |
# Run multiple times to detect flakiness
for i in {1..10}; do npm test 2>&1 | tail -1; done
# Run single test
pytest test_module.py::TestClass::test_method -v
npx vitest run -t "specific test name"
cargo test test_name -- --nocapture
# Run with debugging output
pytest -v --tb=long --capture=no
npx vitest run --reporter=verbose
cargo test -- --nocapture
# Find slow tests
pytest --durations=10
use proptest::prelude::*;
proptest! {
#[test]
fn test_quantity_always_positive(qty in 1i32..1000) {
let item = Item::new("Widget", 10).with_quantity(qty);
assert!(item.subtotal() > 0);
}
}
from hypothesis import given
import hypothesis.strategies as st
@given(st.integers(min_value=1, max_value=1000))
def test_quantity_always_positive(qty):
item = Item("Widget", 10, quantity=qty)
assert item.subtotal() > 0
import * as fc from 'fast-check';
it('quantity always gives positive subtotal', () => {
fc.assert(
fc.property(fc.integer({min: 1, max: 1000}), (qty) => {
const item = new Item('Widget', 10, qty);
expect(item.subtotal()).toBeGreaterThan(0);
})
);
});
| Scenario | Better Alternative |
|---|---|
| Proving mathematical invariants | Proof-driven (Lean 4) |
| Ensuring type safety | Type-driven (Idris 2) |
| Verifying state machine correctness | Validation-first (Quint) |
| Exploratory prototyping | Spike first, then write tests |
| UI visual testing | Screenshot/visual regression tools |
| Already have formal specs | Generate tests from specs |