Навык test-driven-development
Implements the Red-Green-Refactor cycle using a test pyramid of unit, integration, and end-to-end tests with production canary monitoring.
- Звёзды на GitHub
- 16
- Файлы
- 1
- Последний коммит
- 5 окт. 2026 г.
- Лицензия
- MIT
- Разрешённые инструменты
- —
Что делает навык test-driven-development?
test-driven-development — это Agent Skill. Implements the Red-Green-Refactor cycle using a test pyramid of unit, integration, and end-to-end tests with production canary monitoring.
Сводка сгенерирована из SKILL.md навыка.
О skill test-driven-development
Implementing the Red-Green-Refactor cycle is what developers do when they want to ensure code correctness through rigorous test-driven development. This skill follows a specific test pyramid structure, prioritizing a large base of unit tests at 80%, followed by 15% integration tests, and a 5% cap of end-to-end tests. It is designed for engineers who need to maintain high standards during feature development, bug fixing, or refactoring by writing failing tests before any implementation code exists.
An agent should load this skill to manage deployment pipelines and enforce coverage gates, such as requiring 80% line coverage or 90% branch coverage for critical paths. The process relies on DAMP principles to ensure tests are descriptive and meaningful rather than just concise. Beyond the local development cycle, it incorporates canary tests that run synthetic requests in production to verify system health and trigger alarms before customers notice issues.
Что агент может делать с ним
- 1Enforce testing standards via coverage gatesAn AI agent can help configure CI/CD pipelines to block pull requests that do not meet specific coverage thresholds.
- 2Monitor production health with canariesDevelopers can implement synthetic requests that continuously verify real system behavior in a live environment.
- 3Apply DAMP principles to test writingAn engineer can transform unreadable, concise tests into descriptive tests that tell a complete story through the Arrange-Act-Assert structure.
Написано на основе skill SKILL.md. Каждый сценарий использования проверен по цитате из него.
Как установить навык test-driven-development
Каждая команда копирует папку навыка в каталог навыков клиента. Перезапустите клиент или начните новую сессию, чтобы загрузить его.Установка навыка test-driven-development в Плагин
/plugin marketplace add robisson/build-like-amazon-agent-skills /plugin install build-like-amazon@build-like-amazon
Установка навыка test-driven-development в Claude Code
~/.claude/skills/test-driven-development/SKILL.md
$ npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development ~/.claude/skills/test-driven-developmentУстановка навыка test-driven-development в Claude Code (project)
.claude/skills/test-driven-development/SKILL.md
$ npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development .claude/skills/test-driven-developmentУстановка навыка test-driven-development в Codex
~/.agents/skills/test-driven-development/SKILL.md
$ npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development ~/.agents/skills/test-driven-developmentУстановка навыка test-driven-development в Gemini CLI
~/.gemini/skills/test-driven-development/SKILL.md
$ npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development ~/.gemini/skills/test-driven-developmentУстановка навыка test-driven-development в Claude.ai
npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development test-driven-development && zip -r test-driven-development.zip test-driven-development # claude.ai → Customize → Skills → + → Create skill → Upload a skill → test-driven-development.zip
SKILL.md
Открыть на GitHubTest-Driven Development
Overview
Test-Driven Development (TDD) at Amazon means writing the test before the implementation—always. The Red-Green-Refactor cycle is not a suggestion; it is the mechanism that ensures code correctness, enables fearless refactoring, and keeps deployment pipelines green.
Amazon's test philosophy follows the test pyramid: a broad base of fast unit tests (80%), a middle layer of integration tests (15%), and a thin cap of end-to-end tests (5%). This ratio exists because unit tests are fast, deterministic, and cheap to maintain. Integration tests verify contracts between components. End-to-end tests validate customer-visible behavior but are slow and brittle.
Beyond pre-deployment testing, Amazon runs canary tests in production—synthetic requests that continuously verify real system behavior. When canaries fail, alarms fire before customers notice.
When to Use
- Before writing any production code (the "Red" step comes first)
- When fixing a bug (write the failing test that reproduces it first)
- When refactoring existing code (ensure tests exist before changing behavior)
- During code review (verify test coverage for every behavior change)
- When setting up deployment pipelines (configure coverage gates)
- When onboarding a new service (establish canary tests immediately)
Amazon Context
At Amazon, untested code does not ship. Pipelines enforce minimum coverage thresholds (typically 80% line coverage, 90% branch coverage for critical paths). Code review explicitly evaluates test quality—a change without tests is rejected regardless of how correct the implementation appears.
The CI/CD toolchain (build system, deployment pipelines, code analysis) integrates testing at every stage: pre-commit hooks run unit tests locally, CI runs the full suite, and post-deployment canaries verify production health. Teams own their test infrastructure the same way they own their production infrastructure.
Amazon's testing culture learned from expensive failures: services that shipped with "we'll add tests later" invariably accumulated tech debt that made changes risky, deployments scary, and on-call rotations miserable. TDD inverts this—tests are the first thing you build, not the last.
The Process
1. Red-Green-Refactor Cycle
┌─────────────────────────────────────────┐
│ RED: Write a failing test │
│ ↓ │
│ GREEN: Write minimum code to pass │
│ ↓ │
│ REFACTOR: Clean up, tests still pass │
│ ↓ │
│ Repeat │
└─────────────────────────────────────────┘
Red Phase:
- Write one test that describes desired behavior
- Run it. It must fail. If it passes, your test is wrong.
- The test name describes the behavior:
test_order_rejected_when_inventory_zero
Green Phase:
- Write the minimum code to make the test pass
- No premature abstraction. No "while I'm here" changes.
- Hardcode values if that's all the test requires—the next test will force generalization.
Refactor Phase:
- Now clean up both production and test code
- Extract methods, rename variables, remove duplication
- Run tests after every change. All must stay green.
2. Test Pyramid
| Layer | Percentage | Scope | Speed | Characteristics |
|---|---|---|---|---|
| Unit | 80% | Single class/function | < 10ms each | No I/O, no network, no database. Mocked dependencies. |
| Integration | 15% | Component boundaries | < 5s each | Real database (local), real HTTP calls (to test containers). |
| End-to-End | 5% | Full customer journey | < 60s each | Real infrastructure. Fragile. Few but critical. |
3. Writing Effective Unit Tests (DAMP over DRY)
DAMP = Descriptive And Meaningful Phrases. In tests, clarity beats brevity.
# BAD: DRY but unreadable
def test_order(self):
order = self._make_order(status=3, items=2)
self.assertEqual(order.total, self._expected(2))
# GOOD: DAMP - each test tells a complete story
def test_order_total_sums_item_prices_with_tax(self):
order = Order(
items=[
OrderItem(name="Widget", price=Money(10, "USD")),
OrderItem(name="Gadget", price=Money(20, "USD")),
],
tax_rate=Decimal("0.08"),
)
total = order.calculate_total()
assert total == Money(32.40, "USD") # (10 + 20) * 1.08
DAMP principles:
- Arrange-Act-Assert structure in every test (visible sections)
- No shared setup that hides context — if a test needs data, show it in the test
- Test names are documentation —
test_<behavior>_when_<condition>_then_<outcome> - One assertion per test (one logical assertion; multiple
assertcalls for one concept is fine) - Helper factories over fixtures —
make_order(status="pending")beatsself.order
4. Coverage Gates
Configure in CI/CD pipeline:
coverage:
minimum:
line: 80
branch: 80
critical_paths:
line: 95
branch: 90
fail_on_decrease: true
exclude:
- "*/generated/*"
- "*/migrations/*"
Rules:
- Coverage can never decrease on a PR (ratchet mechanism)
- Critical paths (payment, auth, data integrity) require 95%+
- New files must have 90%+ coverage or PR is blocked
- Coverage is measured on production code only (not test code)
5. Test Categories and Tagging
@pytest.mark.unit
def test_calculate_shipping_cost():
...
@pytest.mark.integration
def test_order_persisted_to_dynamodb():
...
@pytest.mark.e2e
def test_customer_can_complete_checkout():
...
@pytest.mark.canary
def test_homepage_loads_under_2_seconds():
...
Execution contexts:
- Pre-commit: Unit tests only (< 30 seconds total)
- CI pipeline: Unit + Integration (< 10 minutes total)
- Pre-deployment: Unit + Integration + E2E (< 30 minutes)
- Production: Canary tests (continuous, every 1-5 minutes)
6. Canary Tests in Production
Canary tests are synthetic requests that exercise real production infrastructure:
class OrderServiceCanary:
"""Runs every 60 seconds against production."""
def test_create_order_happy_path(self):
"""Place a test order and verify it appears in the system."""
order = self.client.create_order(
customer_id=CANARY_CUSTOMER_ID,
items=[CANARY_ITEM],
idempotency_key=f"canary-{uuid4()}",
)
assert order.status == "PLACED"
assert order.id is not None
# Verify read-after-write
retrieved = self.client.get_order(order.id)
assert retrieved.status == "PLACED"
# Cleanup
self.client.cancel_order(order.id, reason="CANARY_TEST")
def test_order_service_latency(self):
"""Verify p99 latency is under SLA."""
start = time.monotonic()
self.client.get_order(KNOWN_ORDER_ID)
latency_ms = (time.monotonic() - start) * 1000
assert latency_ms < 500, f"Latency {latency_ms}ms exceeds 500ms SLA"
Canary rules:
- Use dedicated canary accounts/data (never real customer data)
- Clean up after themselves (no test data accumulation)
- Alert on failure within 5 minutes (high-severity alarm)
- Cover critical customer journeys (top 3-5 paths)
- Run in every region independently
7. Test Quality Checklist
For every PR, verify tests meet the bar:
- Tests fail for the right reason (verified during Red phase)
- Tests are independent (can run in any order)
- Tests are deterministic (no flaky timing dependencies)
- Tests are fast (unit < 10ms, integration < 5s)
- Test names describe behavior, not implementation
- No logic in tests (no
if, no loops, no try/catch) - Mocks verify interactions, not implementation details
- Boundary conditions tested (empty, null, max, overflow)
- Error paths tested (exceptions, timeouts, invalid input)
Mechanisms Over Good Intentions
| Mechanism | What It Enforces | How |
|---|---|---|
| Coverage gates in CI | Minimum test coverage | PR blocked if coverage below threshold or decreases |
| Pre-commit test hooks | Tests run before push | Git hook executes unit tests; push rejected on failure |
| Canary alarm escalation | Production health | PagerDuty alert if canary fails 3 consecutive times |
| Test-to-code ratio metric | Sufficient test investment | Dashboard tracks ratio; reviewed in sprint retrospective |
| Mutation testing (periodic) | Test effectiveness | Monthly mutation run; low mutation kill rate triggers action |
Common Rationalizations
| Rationalization | Why It's Wrong | What To Do Instead |
|---|---|---|
| "I'll add tests after the implementation is stable" | Code without tests is never stable. It's unknown. You'll ship bugs, then write tests around the bugs, cementing them as "expected behavior." | Write the test first. Always. The test defines what "stable" means. |
| "This code is too simple to test" | Simple code becomes complex code. When it does, you'll be afraid to change it. Getters today become business logic tomorrow. | Test the behavior, not the complexity. Simple tests for simple code are fast to write and valuable as documentation. |
| "Mocking makes tests brittle" | Over-mocking makes tests brittle. Strategic mocking at boundaries enables fast, deterministic tests. | Mock at architectural boundaries (database, network, clock). Don't mock internal collaborators—test them together. |
| "100% coverage is our goal" | Coverage measures lines executed, not correctness. 100% coverage with no assertions is useless. Quality over quantity. | Target meaningful coverage: 80% overall, 95% for critical paths. Focus on branch coverage and mutation testing for quality. |
| "End-to-end tests give more confidence" | E2E tests are slow, flaky, and expensive. A failing E2E test tells you something broke but not what. They create false confidence. | Invest in the pyramid. Strong unit tests + focused integration tests give better fault isolation than E2E suites. |
Red Flags
- PR has production code changes but no new or modified tests
- Test suite takes more than 10 minutes to run locally
- Tests break when implementation details change (over-mocking)
- Flaky tests are "retried until green" instead of fixed
- Test names are
test1,test2,testHelper(meaningless) - Tests have complex setup shared across unrelated tests
- Coverage is high but bugs still escape to production (assertion-free tests)
- No canary tests exist for a production service
- Team says "we'll write tests during the hardening sprint"
Verification
After implementing with TDD, verify:
- Every public behavior has at least one test (preferably written first)
- Test pyramid ratios are approximately correct (80/15/5)
- Coverage gates are configured and enforced in CI
- All tests are deterministic (run suite 3x, same results)
- Canary tests are running in production and alarming on failure
- Test suite runs in under 10 minutes in CI
- Mutation testing kill rate is above 70%
- New team members can understand behavior from test names alone
- No test relies on test execution order
Tenets
- Red before Green. Never write production code without a failing test. The test defines the requirement. No test = no requirement = no code.
- Tests are production code. They deserve the same quality, review, and maintenance attention. Sloppy tests create sloppy confidence.
- Fast feedback above all. A test that takes 10 seconds to tell you something is broken is 1000x more valuable than a test that takes 10 minutes.
- DAMP over DRY in tests. Readability and independence matter more than avoiding duplication. Each test is a specification—it should be self-contained.
- Test behavior, not implementation. Tests should survive refactoring. If renaming a private method breaks tests, you're testing the wrong thing.
- Canaries never sleep. Production testing is not optional. If you can't verify your service works right now, you don't know if it works right now.
- Fix flaky tests immediately. A flaky test is worse than no test—it trains the team to ignore failures. Delete it or fix it. Today.
Файлы в этом навыке
1Вопросы о навыке test-driven-development
Как установить навык test-driven-development в Claude Code?
Выполните npx degit robisson/build-like-amazon-agent-skills/skills/test-driven-development ~/.claude/skills/test-driven-development. Claude Code загружает навыки из ~/.claude/skills (все проекты) или .claude/skills (один проект) и использует навык, когда его описание соответствует задаче.
Какие клиенты могут использовать навык test-driven-development?
Любой клиент, который читает формат Agent Skills: Claude Code, Codex, Gemini CLI и claude.ai (загрузить как ZIP). Скрипты в навыке выполняются только там, где клиент разрешает выполнение кода.
What is the recommended distribution for the test pyramid?
The pyramid should consist of 80% unit tests, 15% integration tests, and 5% end-to-end tests.
What does DAMP mean in the context of writing tests?
DAMP stands for Descriptive And Meaningful Phrases, prioritizing clarity and storytelling in tests over code brevity.
What are the standard coverage requirements for CI/CD pipelines?
Pipelines typically enforce a minimum of 80% line coverage and 90% branch coverage for critical paths.