tdd-mastery
Skill0 starsChanged 4 months agoMITView on GitHub
Test-driven development workflow with Red-Green-Refactor cycle across languages
In this repository4 other files it gives its agents.
- git-advancedSkill
- python-best-practicesSkill
- security-hardeningSkill
- testing-strategiesSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 7 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 10
Red: - Write a failing test that defines the desired behavior
- Distinctive: line 11
Green: - Write the minimum code to make the test pass
- Distinctive: line 14
Never write production code without a failing test first.
- Distinctive: line 18
Use the Arrange-Act-Assert pattern consistently:
- Very specific: line 45
Use vi.fn() / jest.fn() for mocks.
- Very specific: line 70
Use pytest.raises for exceptions.
- Very specific: line 101
Use table-driven tests by default.
- Distinctive: line 118
Never write tests just to hit coverage numbers.
- Distinctive: line 135
Never mock the unit under test
- Distinctive: line 136
Prefer fakes (in-memory implementations) over mocks for repositories
- Very specific: line 138
Use t.Cleanup / afterEach to reset shared mocks
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
TDD Mastery
Core Cycle: Red-Green-Refactor
- Red - Write a failing test that defines the desired behavior
- Green - Write the minimum code to make the test pass
- Refactor - Clean up while keeping tests green
Never write production code without a failing test first. Each cycle should take 2-10 minutes.
Test Structure
Use the Arrange-Act-Assert pattern consistently:
Arrange: Set up test data and dependencies
Act: Execute the behavior under test
Assert: Verify the expected outcomeName tests as test_<unit>_<scenario>_<expected_result> or it("should <behavior> when <condition>").
Jest / Vitest Patterns
describe("OrderService", () => {
it("should apply discount when order exceeds threshold", () => {
const order = createOrder({ items: [{ price: 150, qty: 1 }] });
const result = applyDiscount(order, { threshold: 100, percent: 10 });
expect(result.total).toBe(135);
});
it("should throw when applying discount to empty order", () => {
const order = createOrder({ items: [] });
expect(() => applyDiscount(order, defaultDiscount)).toThrow(EmptyOrderError);
});
});Use vi.fn() / jest.fn() for mocks. Prefer dependency injection over module mocking. Use beforeEach for shared setup, never share mutable state between tests.
pytest Patterns
@pytest.fixture
def db_session():
session = create_test_session()
yield session
session.rollback()
def test_create_user_stores_hashed_password(db_session):
user = UserService(db_session).create(email="a@b.com", password="secret")
assert user.password_hash != "secret"
assert verify_password("secret", user.password_hash)
@pytest.mark.parametrize("input,expected", [
("", False),
("short", False),
("ValidPass1!", True),
])
def test_password_validation(input, expected):
assert validate_password(input) == expectedUse pytest.raises for exceptions. Use conftest.py for shared fixtures. Mark slow tests with @pytest.mark.slow.
Go Testing Patterns
func TestParseConfig(t *testing.T) {
tests := []struct {
name string
input string
want Config
wantErr bool
}{
{"valid yaml", "port: 8080", Config{Port: 8080}, false},
{"empty input", "", Config{}, true},
{"invalid port", "port: -1", Config{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseConfig([]byte(tt.input))
if (err != nil) != tt.wantErr {
t.Errorf("ParseConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got != tt.want {
t.Errorf("ParseConfig() = %v, want %v", got, tt.want)
}
})
}
}Use table-driven tests by default. Use t.Helper() in test utility functions. Use testify/assert only if the team already uses it.
Test Levels
| Level | Scope | Speed | Dependencies |
| Unit | Single function/class | <100ms | None (mock all) |
| Integration | Module boundaries | <5s | Real DB, real FS |
| E2E | Full user flow | <30s | Full stack |
Ratio target: 70% unit, 20% integration, 10% e2e.
Coverage Rules
- Enforce 80% line coverage minimum in CI
- Track branch coverage, not just line coverage
- Exclude generated code, type definitions, and config files
- Never write tests just to hit coverage numbers; test behavior
# Jest/Vitest
vitest run --coverage --coverage.thresholds.lines=80 --coverage.thresholds.branches=75
# pytest
pytest --cov=src --cov-fail-under=80 --cov-branch
# Go
go test -coverprofile=cover.out -coverpkg=./... ./...
go tool cover -func=cover.outMocking Guidelines
- Mock at boundaries: HTTP clients, databases, file systems, clocks
- Never mock the unit under test
- Prefer fakes (in-memory implementations) over mocks for repositories
- Assert on behavior, not on mock call counts
- Use
t.Cleanup/afterEachto reset shared mocks
Anti-Patterns to Avoid
- Testing implementation details instead of behavior
- Tests that pass when code is deleted (tautological tests)
- Shared mutable state between test cases
- Ignoring flaky tests instead of fixing them
- Testing private methods directly
- Giant test setup that obscures intent
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

