agentsclimarketplace

Tdd full coverage

Skill troykelly/claude-skills/skills/tdd-full-coverage

Opinionated GitHub-native development workflow with 28 skills for autonomous, issue-driven software development with Claude Code

Install
npx -y skills add troykelly/claude-skills --skill tdd-full-coverage

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 11 stars11 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when implementing features or fixes - test-driven development with RED-GREEN-REFACTOR cycle and full code coverage requirement

SKILL.md

10.1 KB, as published. Nobody here has run it

TDD Full Coverage

Overview

Test-Driven Development with full code coverage.

Core principle: If you didn't watch the test fail, you don't know if it tests the right thing.

Announce at start: "I'm using TDD to implement this feature."

The Iron Law

NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST

Wrote code before a test? Delete it. Start over.

Red-Green-Refactor Cycle

    ┌─────────────────────────────────────────────┐
    │                                             │
    ▼                                             │
┌───────┐     ┌───────┐     ┌──────────┐         │
│  RED  │────►│ GREEN │────►│ REFACTOR │─────────┘
└───────┘     └───────┘     └──────────┘
  Write         Write          Clean
  failing       minimal        up code
  test          code           (stay green)

RED: Write Failing Test

Write ONE test for ONE behavior.

// Test one specific thing
test('rejects empty email', async () => {
  const result = await validateEmail('');
  expect(result.valid).toBe(false);
  expect(result.error).toBe('Email is required');
});

Verify RED: Watch It Fail

MANDATORY. Never skip.

pnpm test --grep "rejects empty email"

Confirm:

  • Test FAILS (not errors)
  • Fails for EXPECTED reason (feature missing, not typo)
  • Error message is what you expect

If test passes → You're testing existing behavior. Fix the test.

GREEN: Minimal Code

Write the SIMPLEST code to pass the test.

function validateEmail(email: string): ValidationResult {
  if (!email) {
    return { valid: false, error: 'Email is required' };
  }
  return { valid: true };
}

Don't add:

  • Error handling for cases you haven't tested
  • Configuration options you don't need yet
  • Optimizations

Verify GREEN: Watch It Pass

MANDATORY.

pnpm test --grep "rejects empty email"

Confirm:

  • Test PASSES
  • All other tests still pass
  • No errors or warnings

REFACTOR: Clean Up

After green, improve code quality:

  • Remove duplication
  • Improve names
  • Extract helpers

Keep tests green during refactoring.

Repeat

Write next failing test for next behavior.

Coverage Requirements

Target: 100% for New Code

# Check coverage
pnpm test --coverage

# Verify new code is covered
# Lines: 100%
# Branches: 100%
# Functions: 100%
# Statements: 100%

What 100% Means

CoveredNot Covered (Fix It)
All branches testedSome if/else paths missed
All functions calledUnused functions
All error handlers triggeredError paths untested
All edge cases verifiedOnly happy path

Acceptable Exceptions

These MAY have lower coverage (discuss with team):

  • Configuration files
  • Type definitions only
  • Auto-generated code
  • Third-party integration code (mock at boundary)

Document exceptions in coverage config:

// jest.config.js
module.exports = {
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },
  coveragePathIgnorePatterns: [
    '/node_modules/',
    '/generated/',
    'config.ts',
  ],
};

Integration Testing Against Local Services

Core principle: Unit tests with mocks are necessary but not sufficient. You MUST ALSO test against real services.

The Two-Layer Testing Requirement

LayerPurposeUses Mocks?Uses Real Services?
Unit Tests (TDD)Verify logic, enable RED-GREEN-REFACTORYESNo
Integration TestsVerify real service behaviorNoYES

Both layers are REQUIRED. Unit tests alone miss real-world failures. Integration tests alone are too slow for TDD.

The Problem We're Solving

We've experienced 80% failure rates with ORM migrations because:

  • Unit tests with mocks pass
  • Real database rejects the migration
  • CI discovers the bug instead of local testing

Mocks don't catch: Schema mismatches, constraint violations, migration failures, connection issues, transaction behavior.

When Integration Tests Are Required

Code ChangeUnit Tests (with mocks)Integration Tests (with real services)
Database model/migration✅ RequiredAlso required
Repository/ORM layer✅ RequiredAlso required
Cache operations✅ RequiredAlso required
Pub/sub messages✅ RequiredAlso required
Queue workers✅ RequiredAlso required

Local Service Testing Protocol

After completing TDD cycle (unit tests with mocks):

  1. Ensure services are running (docker-compose up -d)
  2. Run integration tests against real services
  3. Verify migrations apply (pnpm migrate)
  4. Verify in local environment before pushing

Example: Database Testing

// LAYER 1: Unit tests with mocks (TDD cycle)
describe('UserRepository (unit)', () => {
  const mockDb = { query: jest.fn() };

  it('calls correct SQL for findById', async () => {
    mockDb.query.mockResolvedValue([{ id: 1, email: '[email protected]' }]);
    const user = await userRepo.findById(1);
    expect(mockDb.query).toHaveBeenCalledWith('SELECT * FROM users WHERE id = $1', [1]);
  });
});

// LAYER 2: Integration tests with real postgres (ALSO required)
describe('UserRepository (integration)', () => {
  beforeAll(async () => {
    await db.migrate.latest();
  });

  it('actually persists and retrieves users', async () => {
    await userRepo.create({ email: '[email protected]' });
    const user = await userRepo.findByEmail('[email protected]');
    expect(user).toBeDefined();
    expect(user.email).toBe('[email protected]');
  });

  it('enforces unique email constraint', async () => {
    await userRepo.create({ email: '[email protected]' });
    // Real postgres will throw - mocks won't catch this
    await expect(
      userRepo.create({ email: '[email protected]' })
    ).rejects.toThrow(/unique constraint/);
  });
});

Skill: local-service-testing

Test Quality

Good Tests

// GOOD: Clear name, tests one thing
test('calculates tax for positive amount', () => {
  const result = calculateTax(100, 0.08);
  expect(result).toBe(8);
});

test('returns zero tax for zero amount', () => {
  const result = calculateTax(0, 0.08);
  expect(result).toBe(0);
});

test('throws for negative amount', () => {
  expect(() => calculateTax(-100, 0.08)).toThrow('Amount must be positive');
});

Bad Tests

// BAD: Tests multiple things
test('calculateTax works', () => {
  expect(calculateTax(100, 0.08)).toBe(8);
  expect(calculateTax(0, 0.08)).toBe(0);
  expect(() => calculateTax(-100, 0.08)).toThrow();
});

// BAD: Tests mock, not real code
test('calls the tax service', () => {
  const mockTaxService = jest.fn().mockReturnValue(8);
  const result = calculateTax(100, 0.08);
  expect(mockTaxService).toHaveBeenCalled();  // Testing mock, not behavior
});

Testing Patterns

Arrange-Act-Assert

test('description', () => {
  // Arrange - set up test data
  const user = createTestUser({ email: '[email protected]' });
  const input = { userId: user.id, action: 'update' };

  // Act - perform the action
  const result = processAction(input);

  // Assert - verify the outcome
  expect(result.success).toBe(true);
  expect(result.timestamp).toBeDefined();
});

Testing Errors

test('throws for invalid input', () => {
  expect(() => validateInput(null)).toThrow(ValidationError);
  expect(() => validateInput(null)).toThrow('Input is required');
});

test('async throws for invalid input', async () => {
  await expect(asyncValidate(null)).rejects.toThrow(ValidationError);
});

Testing Side Effects

test('logs error on failure', async () => {
  const logSpy = jest.spyOn(logger, 'error');

  await processWithFailure();

  expect(logSpy).toHaveBeenCalledWith(
    expect.stringContaining('Failed to process')
  );
});

Mocking Guidelines

When to Mock

MockDon't Mock
External APIsYour own code
Database (integration)Simple functions
File systemPure logic
Time/datesDeterministic code
Network requestsInternal modules

Mock at Boundaries

// GOOD: Mock the external boundary
const fetchMock = jest.spyOn(global, 'fetch').mockResolvedValue(
  new Response(JSON.stringify({ data: 'test' }))
);

// BAD: Mock internal implementation
const internalMock = jest.spyOn(utils, 'internalHelper');

Debugging Test Failures

ProblemSolution
Test passes when should failCheck assertion (expect syntax)
Test fails unexpectedlyCheck test isolation (cleanup)
Flaky testsRemove timing dependencies
Hard to testImprove code design

Checklist

Before completing a feature:

  • Every function has at least one test
  • Watched each test fail before implementing
  • Each failure was for expected reason
  • Wrote minimal code to pass
  • All tests pass
  • Coverage is 100% for new code
  • No skipped tests
  • Tests are isolated (no order dependency)
  • Error cases are tested
  • Integration tests ran against local services (not mocks)
  • All service-dependent code verified locally

Integration

This skill is called by:

  • issue-driven-development - Step 7, 8, 11

This skill uses:

  • strict-typing - Tests should be typed
  • inline-documentation - Document test utilities

This skill ensures:

  • Verified behavior
  • Regression prevention
  • Refactoring safety
  • Documentation through tests

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.