Vertical Slice TDD with Tracer Bullets
Build features one tested behavior at a time, starting with a tracer bullet that proves the required path works.
Before & after
Same prompt, same agent — the only difference is the skill.
For TDD, you'd normally write tests first before implementing the code. You could start with a failing test and then write code to make it pass. Vertical slices mean building small, complete features rather than layers. That's generally a good approach. You might need to decide what framework to use for testing. Would it be better to start with unit tests, integration tests, or end-to-end tests? And should I write all the tests first or add them as I go?
TDD VERTICAL SLICE: OAuth2 Token Refresh
TRACER BULLET 1: END-TO-END TEST (Red)
Write test first, no implementation:
test('POST /auth/refresh returns new access token with valid refresh token', async () => {
const refreshToken = 'old_refresh_token_expires_2026_08_31';
const response = await client.post('/auth/refresh', { refreshToken });
expect(response.status).toBe(200);
expect(response.body.accessToken).toBeDefined();
expect(response.body.expiresIn).toBe(3600);
});
Run test: FAILS (no POST /auth/refresh endpoint)
TRACER BULLET 2: MINIMAL IMPLEMENTATION (Green)
Write only enough code to pass test:
app.post('/auth/refresh', (req, res) => {
res.json({ accessToken: 'dummy_token', expiresIn: 3600 });
});
Run test: PASSES (test is now green)
TRACER BULLET 3: ITERATE (Refactor)
Add next test for edge case:
test('POST /auth/refresh returns 401 with expired refresh token', async () => {
const expiredToken = 'old_refresh_token_expires_2026_07_30';
const response = await client.post('/auth/refresh', { refreshToken: expiredToken });
expect(response.status).toBe(401);
expect(response.body.error).toBe('Refresh token expired');
});
Run test: FAILS (token validation not implemented)
Add validation logic:
app.post('/auth/refresh', (req, res) => {
const { refreshToken } = req.body;
const decoded = jwt.verify(refreshToken, SECRET); // Throws if expired
if (decoded.exp < Date.now() / 1000) {
return res.status(401).json({ error: 'Refresh token expired' });
}
const newToken = jwt.sign({ userId: decoded.userId }, SECRET, { expiresIn: '1h' });
res.json({ accessToken: newToken, expiresIn: 3600 });
});
Run test: PASSES
TRACER BULLET 4: NEXT VERTICAL SLICE
Don't build adjacent features yet (persistence layer, UI, etc.)
Instead, write next end-to-end test for next slice:
test('POST /auth/refresh increments token version (prevent replay attacks)', ...);
test('POST /auth/refresh logs revocation event to audit table', ...);
Each test spawns its own implementation. Build width (features) incrementally, not depth (layers).
WHY THIS WORKS
• Tests remain always-passing (no broken tests accruing)
• Each feature complete and tested before next starts
• No large refactors at the end (refactoring happens per-slice)
• Easy to show progress ("3 features passing" vs "infrastructure 80% done")
WHEN TO STOP SLICING
Stop when:
✓ All user-facing flows have passing tests
✓ Happy path + 2-3 error cases per feature
✓ No more than 20 lines per test function (if test >20 lines, feature too big)
About this skill
Your tests pass, but the feature still doesn't work across its layers. Or the implementation grows for hours before anything runs. This workflow starts with a tracer bullet that proves one useful path, then expands it through small, verified test-first changes.
What it does
- Turns a feature request into observable behaviors ordered by dependency and integration risk.
- Chooses a first test that crosses the boundaries the feature actually needs.
- Distinguishes an expected behavior failure from a broken test harness or missing dependency.
- Keeps each cycle to one failing behavior and the smallest implementation that satisfies it.
- Uses real internal collaborators while isolating external services at their adapters.
- Records what each test proves, which checks ran, and what remains unverified.
What you get
An incrementally implemented feature or bug fix, with regression tests and concise verification evidence. For planning or review requests, you get a concrete first slice and an ordered progression of testable behaviors.
Best for
Developers using Claude Code to build features, repair bugs, or recover from speculative implementations that passed isolated tests but failed when connected.
SKILL.md preview
---
name: vertical-slice-tdd-with-tracer-bullets
description: >-
Build features through vertical slices: prove one thin path across required boundaries, then add one behavior per observed red-green-refactor cycle. Use when the user says "build this test first", "add this feature with TDD", "my tests pass but the feature doesn't work", "we built too much before testing", "start with a tracer bullet", "fix this bug with a regression test", or "review our TDD approach".
---
# Vertical Slice TDD with Tracer Bullets
… (sign up to view the full skill)More development skills
View all Development skills →React and Next.js Regression Test Coverage
Generate React and Next.js tests with Jest, Testing Library, MSW, and Playwright, prioritized by regression risk.
Playwright E2E Tests and Flake Repair
Build reliable Playwright tests, repair flakes from evidence, migrate suites, and configure faster, diagnosable CI.
Pre-Ship Verification for Code Changes
Before calling a code change done, Claude grades every claim by evidence, tries to break it, and reports what's verified vs assumed.
TestRail Case and CI Result Sync
Sync automated tests to TestRail cases and scoped runs with stable mappings, retry handling, and verified result counts.