Claude
Skills
Sign in
Back

test

Included with Lifetime
$97 forever

Generate tests and coverage plans.

Code Review

What this skill does

# Test Skill

> **Quick Ref:** Generate tests, analyze coverage, fill gaps, run TDD loops. Output: passing tests + coverage report in `.agents/test/`.

**YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.**

Generate real tests, run them, verify they pass, and produce coverage artifacts. Do not output a plan and stop.

## Modes

| Mode | Trigger | What It Does |
|------|---------|--------------|
| `generate` | "generate tests", "write tests", "add tests" | Create tests for existing code |
| `coverage` | "test coverage", "coverage gaps", "missing tests" | Analyze coverage and fill gaps |
| `strategy` | "test strategy", "test architecture" | Recommend test structure and patterns |
| `tdd` | "tdd", "red green refactor" | Red-green-refactor loop for new features |

Default mode is `generate` when unspecified. Detect from user intent.

## Step 0a: Scenarios-First (when the work has acceptance scenarios)

When the task is tied to a bead or `.feature` file, **author tests FORWARD from the Gherkin scenarios** — not backward from a coverage gap. This is the C2 contract (ag-9jle.4): the unit of test authoring is one scenario, one covering test.

1. Read the scenarios: the bead's `## Scenarios` block (`bd show <bead-id>`) or a `.feature` under `skills/<skill>/references/`.
2. For each `Scenario:`, locate or write the test that exercises its `Given/When/Then`. Name it after the behavior.
3. Declare the linkage by adding `@covered-by:<test-path>` (optionally `::<TestName>`) directly above the scenario in its source — so the leaf coverage gate can prove the mapping.
4. Run the leaf coverage gate and require it to pass before considering the slice tested:

```bash
bash scripts/check-bead-scenario-coverage.sh --bead <bead-id> --run      # every scenario -> a PASSING test
bash scripts/check-bead-scenario-coverage.sh skills/<skill>/references/<name>.feature --run
```

A scenario with no covering test is a FAIL — "tests exist" or a coverage percentage is not sufficient. Then continue with coverage gap-fill (Steps 1–5) for everything the scenarios don't reach. When there are no scenarios, skip this step and use the coverage-driven flow below.

## Step 0: Detect Language and Load Standards

Scan the project root for language markers. Stop at the first match:

| Marker File | Language | Test Framework | Coverage Command |
|-------------|----------|----------------|-----------------|
| `go.mod` | Go | `go test` | `go test -coverprofile=coverage.out ./...` |
| `pyproject.toml` or `setup.py` | Python | pytest | `pytest --cov --cov-report=term-missing` |
| `package.json` | JS/TS | jest or vitest | `npx jest --coverage` or `npx vitest run --coverage` |
| `Cargo.toml` | Rust | cargo test | `cargo tarpaulin --out Lcov` |

Load `/standards` for the detected language. Apply all testing conventions from the standards skill (naming, assertion style, structural rules).

**Go-specific rules (from project CLAUDE.md):**
- Test file naming: `<source>_test.go`. NEVER `cov*_test.go` or `*_extra_test.go`.
- Test function naming: `Test<Uppercase>` (e.g., `TestParseConfig_EmptyInput`).
- Prefer table-driven tests for multi-case functions.
- Use `captureStdout` for output functions and assert content.

**Python-specific rules:**
- Use `pytest` with `conftest.py` for shared fixtures.
- Use `@pytest.mark.parametrize` for multi-case functions.
- Type hints on test helpers.

**JS/TS-specific rules:**
- Use `describe`/`it` blocks with clear names.
- Group by function or module under test.
- Mock external services, not internal code.

## Step 1: Analyze Existing Test Coverage

Run the coverage command for the detected language:

```bash
# Go
go test -coverprofile=coverage.out ./... 2>&1 | tee .agents/test/coverage-raw.txt
go tool cover -func=coverage.out > .agents/test/coverage-func.txt

# Python
pytest --cov --cov-report=term-missing --cov-report=json:.agents/test/coverage.json 2>&1 | tee .agents/test/coverage-raw.txt

# JS/TS
npx jest --coverage --coverageReporters=text 2>&1 | tee .agents/test/coverage-raw.txt

# Rust
cargo tarpaulin --out Lcov 2>&1 | tee .agents/test/coverage-raw.txt
```

Parse the output. Build a ranked list of files by coverage percentage (lowest first).

If `/complexity` is available, cross-reference: high-complexity + low-coverage = highest priority targets.

## Step 2: Identify Gaps

From the coverage data, identify:

1. **Untested files** -- source files with no corresponding test file.
2. **Uncovered functions** -- exported/public functions with 0% coverage.
3. **Uncovered branches** -- functions with partial coverage (conditionals, error paths).
4. **Missing edge cases** -- functions that only test the happy path.

Produce a gap list sorted by risk (high complexity + low coverage first):

```
File                        | Coverage | Functions Missing Tests | Risk
----------------------------|----------|------------------------|------
internal/parser/parse.go    | 23%      | ParseConfig, Validate  | HIGH
internal/goals/measure.go   | 45%      | MeasureFitness         | MEDIUM
lib/utils.go                | 89%      | (edge cases only)      | LOW
```

Write gap list to `.agents/test/gaps.md`.

## Step 3: Generate Tests

For each gap (highest risk first), generate tests following language-specific patterns.

If the target needs a specialized test pattern, load the matching reference before writing tests:

- Contract/API/CLI compatibility: [references/conformance-harnesses.md](references/conformance-harnesses.md)
- Parsers, serializers, and untrusted inputs: [references/fuzzing.md](references/fuzzing.md)
- Generated files, snapshots, and rendered output: [references/golden-artifacts.md](references/golden-artifacts.md)
- Metamorphic/invariant-heavy behavior: [references/metamorphic-testing.md](references/metamorphic-testing.md)
- Golden artifact update review: [references/golden-artifact-strategy.md](references/golden-artifact-strategy.md)
- Real databases, services, queues, or APIs where mocks would hide failures: [references/real-service-e2e.md](references/real-service-e2e.md)

### Go: Table-Driven Tests

```go
func TestParseConfig_Variants(t *testing.T) {
    tests := []struct {
        name    string
        input   string
        want    *Config
        wantErr bool
    }{
        {name: "valid minimal", input: `name: foo`, want: &Config{Name: "foo"}},
        {name: "empty input", input: "", want: nil, wantErr: true},
        {name: "invalid yaml", input: `: bad`, want: nil, wantErr: true},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := ParseConfig(tt.input)
            if (err != nil) != tt.wantErr {
                t.Errorf("ParseConfig() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if !reflect.DeepEqual(got, tt.want) {
                t.Errorf("ParseConfig() = %v, want %v", got, tt.want)
            }
        })
    }
}
```

### Python: Parametrized Tests

```python
@pytest.mark.parametrize("input_val,expected", [
    ("valid", Config(name="valid")),
    ("", None),
    (None, None),
])
def test_parse_config(input_val: str, expected: Config | None) -> None:
    result = parse_config(input_val)
    assert result == expected
```

### JS/TS: Describe Blocks

```typescript
describe("parseConfig", () => {
  it("parses valid input", () => {
    expect(parseConfig("valid")).toEqual({ name: "valid" });
  });

  it("returns null for empty input", () => {
    expect(parseConfig("")).toBeNull();
  });

  it("throws on malformed input", () => {
    expect(() => parseConfig(": bad")).toThrow();
  });
});
```

### Generation Rules

1. **Read the source function first.** Understand inputs, outputs, error conditions, and branches.
2. **Cover every branch.** Each `if`, `switch`, error return, and edge case gets at least one test case.
3. **Assert exact expected values.** Use `== expected`, not `!= nil` or `!= ""`.
4. **Name tests descriptively.** The test name should describe
Files: 1
Size: 15.5 KB
Complexity: 22/100
Category: Code Review

Related in Code Review