developing-with-tdd
SkillWeb & browsingTest-Driven Development for backend code. Red-Green-Refactor cycle with practical patterns.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the developing-with-tdd skill
What this skill tells your AI
The instructions your AI receives, as published by porcupine-md/anoa-browser in .claude/skills/library/backend/developing-with-tdd/SKILL.md and read by ahel’s review.
TDD Cycle
Red → Green → Refactor
- Red: Write a failing test that describes desired behavior
- Green: Write the minimum code to make it pass (no gold-plating)
- Refactor: Improve the code without changing behavior (tests stay green)
Never skip to Green without a failing Red test first.
Practical Rules
Rule 1: One test at a time Write one failing test. Make it pass. Only then write the next test.
Rule 2: Minimum viable production code In Green phase, write only what's needed to pass the test. No future-proofing.
Rule 3: Test behavior, not implementation
Bad: expect(user._hash).toBeDefined()
Good: expect(await user.verifyPassword('secret')).toBe(true)
Rule 4: Fast tests Unit tests must run in <100ms. Use mocks for I/O (database, network, filesystem).
Structure
src/
auth/
auth.service.ts ← Implementation
auth.service.test.ts ← Tests (co-located)
Test Template (TypeScript/Vitest)
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
service = new AuthService({ /* mock deps */ });
});
describe('login()', () => {
it('returns a JWT token for valid credentials', async () => {
// Arrange
const credentials = { email: 'user@test.com', password: 'correct' };
// Act
const result = await service.login(credentials);
// Assert
expect(result.token).toMatch(/^eyJ/);
});
it('throws for invalid password', async () => {
await expect(service.login({ email: 'user@test.com', password: 'wrong' }))
.rejects.toThrow('Invalid credentials');
});
});
});
Mocking External Dependencies
// Mock the database
const mockUserRepo = {
findByEmail: vi.fn().mockResolvedValue({ id: '1', email: 'user@test.com', passwordHash: '$2b...' }),
};
When to Stop TDD
- Configuration files
- Simple data transformations (use property-based testing instead)
- Exploratory code (spike) — delete tests after learning, rewrite properly
Definition of Done
- All tests pass
- No test mocks real behavior (only I/O)
- Coverage ≥ 80% on the changed module
- Tests run in < 1 second total
Signals
- GitHub stars
- 23
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
developing-with-tdd- Source
- github.com/porcupine-md/anoa-browser