본문으로 건너뛰기
cccskills
무료GitHub에 공개

tdd

Enforce test-driven development with RED→GREEN→REFACTOR cycle and coverage validation

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core스타 90(GitHub 90 + cccskills 0)

실행 점수 미검증

설치 방법 보기

포함된 파일(2)

  • SKILL.md14.0 KB
  • agents/openai.yaml111 B

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

/tdd - Test-Driven Development Workflow

Develop a feature using strict test-driven development: write failing tests first, implement minimal code, refactor, and verify coverage.

What a good test is: tests verify behavior through public interfaces, read like a specification, and survive refactors.

Task description: $ARGUMENTS

TDD Cycle (MANDATORY)

RED → GREEN → REFACTOR → REPEAT
  1. RED: Write a failing test FIRST (verify test fails before implementation)
  2. GREEN: Write minimal code to pass the test (no over-engineering)
  3. REFACTOR: Improve code quality while keeping tests green
  4. REPEAT: Continue until feature is complete and coverage meets requirements

Seams — where tests go

A seam is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals.

Test only at pre-agreed seams. Before writing any test, write down the seams under test and confirm them with the user. No test is written at an unconfirmed seam. You can't test everything — agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case.

Ask: "What's the public interface, and which seams should we test?" Give each proposed seam a one-line note on what it catches and what it misses.


Process

Step 1: Framework Detection & Setup

Auto-detect the test framework and package manager from the project:

Package managers (check in priority order):

  • bun.lockb → bun test
  • pnpm-lock.yaml → pnpm test
  • yarn.lock → yarn test
  • package-lock.json → npm test
  • Cargo.lock → cargo test
  • go.mod → go test ./...

Test frameworks (infer from project files):

  • package.json with jest → Jest (Node/TypeScript)
  • package.json with vitest → Vitest (Vite-based)
  • pyproject.toml or requirements.txt → pytest (Python)
  • go.mod → Go's testing package
  • Cargo.toml → Rust's built-in test framework

If no framework detected: Ask the user which test framework and runner to use. Do not proceed without a confirmed test runner.

Store the detected runner as {TEST_CMD} (e.g., bun test, pnpm test, pytest) and use it for all subsequent test commands in this workflow.

Report detected framework and package manager to the user before proceeding.

Step 2: Define Interfaces (Scaffold)

Create the function/class definition with empty implementation:

  • Write TypeScript interfaces (or equivalent) for inputs and outputs
  • Define the function signature with placeholder implementation
  • Include JSDoc comments describing behavior

Example (TypeScript):

/**
 * Validates an email address format.
 * @param email - The email string to validate
 * @returns true if email is valid, false otherwise
 * @throws Error if email is null/undefined
 */
export function validateEmail(email: string): boolean {
  throw new Error('Not implemented');
}

Step 3: Write Failing Tests (RED Phase)

Read <repo>/GLOSSARY.md if present so test names and interface vocabulary match the project's domain language (ties into /domain-modeling).

Write comprehensive test suite BEFORE implementation:

Test types to include:

  • Happy path (valid input → expected output)
  • Edge cases (empty, null, undefined, boundary values, max length)
  • Error conditions (invalid formats, type errors)
  • Integration tests (API endpoints, database operations if applicable)

Requirements:

  • Tests must FAIL before implementation
  • Each test should be independent (no shared state)
  • Use meaningful assertion messages
  • Run tests and VERIFY RED status (all fail as expected)

Example test structure (Jest/Vitest):

describe('validateEmail', () => {
  describe('happy path', () => {
    it('accepts valid email addresses', () => {
      expect(validateEmail('user@example.com')).toBe(true);
      expect(validateEmail('test.name+tag@domain.co.uk')).toBe(true);
    });
  });

  describe('edge cases', () => {
    it('rejects empty string', () => {
      expect(validateEmail('')).toBe(false);
    });

    it('rejects email without @', () => {
      expect(validateEmail('invalidemail.com')).toBe(false);
    });

    it('rejects email without domain', () => {
      expect(validateEmail('user@')).toBe(false);
    });

    it('rejects email with spaces', () => {
      expect(validateEmail('user @example.com')).toBe(false);
    });

    it('handles special characters', () => {
      expect(validateEmail('user+tag@example.com')).toBe(true);
      expect(validateEmail('user.name@sub.domain.com')).toBe(true);
    });
  });

  describe('error conditions', () => {
    it('throws error if email is null', () => {
      expect(() => validateEmail(null as any)).toThrow();
    });

    it('throws error if email is undefined', () => {
      expect(() => validateEmail(undefined as any)).toThrow();
    });

    it('rejects excessively long email', () => {
      const longEmail = 'a'.repeat(255) + '@example.com';
      expect(validateEmail(longEmail)).toBe(false);
    });
  });
});

Run tests and verify RED:

{TEST_CMD}        # Use the detected test runner from Step 1
# Expected: ALL tests FAIL (red output)
# If ANY test passes, you haven't written the test correctly — fix it before proceeding

Step 4: Implement Minimal Code (GREEN Phase)

Write only the minimum code needed to pass the tests:

  • No premature optimization
  • No extra features beyond test requirements
  • Focus on making tests pass
  • Keep code simple and readable

Example minimal implementation:

export function validateEmail(email: string): boolean {
  if (email === null || email === undefined) {
    throw new Error('Email cannot be null or undefined');
  }

  if (email.length === 0 || email.length > 254) {
    return false;
  }

  // Basic email regex pattern
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

Run tests and verify GREEN:

{TEST_CMD}        # Use the detected test runner from Step 1
# Expected: ALL tests PASS (green output)

Step 5: Refactor (IMPROVE Phase)

Improve code quality while keeping tests green:

  • Extract constants and magic strings
  • Improve variable/function names
  • Remove duplication
  • Optimize performance (if needed)
  • Add comments for complex logic

Requirements:

  • Run tests after each refactoring step
  • Verify all tests still PASS
  • Refactoring should not add new functionality
  • Keep in-loop refactors small and local. For deeper structural refactors (moving seams, reshaping modules), hand off to /review rather than expanding this cycle.

Example refactored implementation:

const EMAIL_MAX_LENGTH = 254;
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

/**
 * Validates an email address format following RFC 5321 basic rules.
 * @param email - The email string to validate
 * @returns true if email matches expected format, false otherwise
 * @throws Error if email is null or undefined
 */
export function validateEmail(email: string): boolean {
  if (email == null) {
    throw new Error('Email cannot be null or undefined');
  }

  if (email.length === 0 || email.length > EMAIL_MAX_LENGTH) {
    return false;
  }

  return EMAIL_PATTERN.test(email);
}

Run tests after EACH refactoring step:

{TEST_CMD}        # Use the detected test runner from Step 1
# Expected: ALL tests still PASS (green output)
# Refactor one concern at a time. Stop when code is clean and readable.

Step 6: Verify Coverage

Check code coverage and add tests for any uncovered paths:

Coverage requirements by code type:

Code TypeMinimum Coverage
Standard application code80%
Financial calculations100%
Authentication/authorization100%
Security-critical code100%
Encryption/decryption100%

Run coverage check:

# Jest
npm test -- --coverage

# Vitest
npx vitest run --coverage

# pytest
pytest --cov=. --cov-report=term-missing

# Go
go test -cover ./...

# Rust
cargo tarpaulin --out Html

Acceptance criteria:

  • Lines covered: ≥ target percentage
  • Branches covered: ≥ target percentage
  • Functions covered: ≥ target percentage
  • Any uncovered lines documented with rationale (if intentional)

If coverage is below target:

  1. Identify uncovered code paths
  2. Write additional tests for those paths
  3. Run tests again (verify GREEN)
  4. Re-check coverage

Worked Example: Email Validator (Complete Walkthrough)

RED Phase Output

$ npm test

FAIL  src/email-validator.test.ts
  validateEmail
    happy path
      ✕ accepts valid email addresses (0ms)
      ✕ accepts variation formats (1ms)
    edge cases
      ✕ rejects empty string (0ms)
      ✕ rejects email without @ (1ms)
      ✕ rejects email without domain (0ms)
      ✕ rejects email with spaces (0ms)
      ✕ handles special characters (1ms)
    error conditions
      ✕ throws error if email is null (0ms)
      ✕ throws error if email is undefined (0ms)
      ✕ rejects excessively long email (0ms)

Tests:       0 passed, 10 failed, 10 total

GREEN Phase Output (After Implementation)

$ npm test

PASS  src/email-validator.test.ts
  validateEmail
    happy path
      ✓ accepts valid email addresses (2ms)
      ✓ accepts variation formats (1ms)
    edge cases
      ✓ rejects empty string (0ms)
      ✓ rejects email without @ (0ms)
      ✓ rejects email without domain (1ms)
      ✓ rejects email with spaces (0ms)
      ✓ handles special characters (1ms)
    error conditions
      ✓ throws error if email is null (0ms)
      ✓ throws error if email is undefined (0ms)
      ✓ rejects excessively long email (0ms)

Tests:       10 passed, 10 total (18ms)

Coverage Report (After Implementation & Refactoring)

$ npm test -- --coverage

------------|----------|----------|----------|----------|-------------|
File        | % Stmts  | % Branch | % Funcs  | % Lines   | Uncovered   |
------------|----------|----------|----------|----------|-------------|
All files   |   100    |   100    |   100    |   100     |             |
 email-...ts |   100    |   100    |   100    |   100     |             |
------------|----------|----------|----------|----------|-------------|

Anti-Patterns to Avoid

  • Testing implementation details: Test behavior, not internal state
  • Shared test state: Each test must be independent (no beforeAll side effects)
  • Insufficient assertions: Verify specific outputs, not just "no error"
  • Untested error paths: Include tests for error conditions, not just happy path
  • No mocking of external dependencies: Mock API calls, database, file system, etc.
  • Skipped tests: Never commit xit() or .skip — fix the test or remove it
  • Tautological: The assertion recomputes the expected value the way the code does (expect(add(a, b)).toBe(a + b), or a snapshot derived by hand the same way) — it passes by construction and can never disagree with the code. Expected values must come from an independent source of truth (a known-good literal, a worked example, the spec).
  • Horizontal slicing: Writing all tests first, then all implementation. Bulk tests verify imagined behavior and commit you to test structure before you understand the implementation. Work in vertical slices instead — one test → one implementation → repeat, each test a tracer bullet that responds to what the last cycle taught you.

Tips for Success

  1. Write tests first, always — This forces you to think about the interface before implementation
  2. Fail fast — The RED phase should show clear test failures before coding
  3. Minimal code — The simplest code that passes tests is usually the best code
  4. Refactor fearlessly — Tests are your safety net; they prevent regressions
  5. Coverage is a tool, not a goal — 80% coverage is a checkpoint, not a target
  6. Test the interface, not the implementation — Users care about behavior, not how you achieve it

Framework-Specific Commands

Jest (Node.js/TypeScript)

# Run all tests
npm test

# Run tests in watch mode
npm test -- --watch

# Run coverage
npm test -- --coverage

# Run specific test file
npm test email-validator.test.ts

Vitest (Vite/TypeScript)

# Run all tests
npx vitest run

# Run tests in watch mode
npx vitest

# Run coverage
npx vitest run --coverage

# Run specific test file
npx vitest email-validator.test.ts

pytest (Python)

# Run all tests
pytest

# Run tests in watch mode
pytest --lf (runs last-failed)

# Run coverage
pytest --cov=. --cov-report=term-missing

# Run specific test file
pytest tests/test_email_validator.py

go test (Go)

# Run all tests
go test ./...

# Run with verbose output
go test -v ./...

# Run coverage
go test -cover ./...

# Run specific test
go test -run TestValidateEmail ./...

cargo test (Rust)

# Run all tests
cargo test

# Run tests in release mode
cargo test --release

# Run with coverage (requires tarpaulin)
cargo tarpaulin --out Html

# Run specific test
cargo test validate_email

Success Checklist

After completing the TDD workflow, verify:

  • Framework detected correctly
  • Tests written BEFORE implementation (RED phase confirmed)
  • All tests PASS (GREEN phase confirmed)
  • Code refactored for clarity and quality
  • Coverage meets requirements (80%+ standard, 100% for critical paths)
  • Test suite includes: happy path, edge cases, error conditions
  • No shared state between tests
  • Meaningful assertion messages
  • Code committed with comprehensive test suite

Upstream

Seam and anti-pattern guidance adapted from mattpocock/skills (skills/engineering/tdd), synced to upstream commit f3fc563. HQ keeps its RED, GREEN, REFACTOR cycle and coverage gates.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

accept

무료

Accept HQ membership invites from a magic link or raw token.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

adr

무료

Capture qualifying architecture decisions as ADRs in the right HQ or repo location.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

architect

무료

Find shallow modules and propose deepening refactors, ranked with file refs; never edits code. Use when code is hard to change or planning a refactor.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

Generate dark ASCII banner graphics for HQ and social launch assets.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

Compare approaches to best-in-class prior art, merge existing work, verify cruft removal, and recommend the most durable design before PRD work.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

indigoai-us/hq-core902026년 10월 26일 업데이트

indigoai-us의 스킬 모두 보기

이 스킬의 문제 신고