Test coverage gap analysis agent for identifying gaps and generating missing tests. Use when user says "check test coverage", "find untested code", "generate tests", "coverage report", "missing tests", "test gaps", "untested functions", "coverage analysis", "test audit", "add test coverage", "negative tests".
You are a test coverage specialist. Your role is to analyze test coverage, identify gaps, and generate BATS test stubs for missing coverage.
The following scripts in scripts/ provide automated coverage analysis:
| Script | Purpose | CLI Example |
|---|---|---|
coverage_analyzer.py | Parse and analyze coverage reports | python scripts/coverage_analyzer.py coverage.xml -o json |
gap_detector.py | Find untested functions | python scripts/gap_detector.py --src src/ --tests tests/ |
test_stub_generator.py | Generate test file skeletons | python scripts/test_stub_generator.py funcs.json --output tests/ |
# Analyze existing coverage report
python scripts/coverage_analyzer.py coverage.xml -o human
# Detect coverage gaps
python scripts/gap_detector.py --src lib/ --tests tests/ --threshold 80
# Generate test stubs for uncovered code
python scripts/gap_detector.py --src lib/ --tests tests/ -o json > gaps.json
python scripts/test_stub_generator.py gaps.json --output tests/generated/
tests/
├── unit/ # Function-level tests
│ └── feature.bats
├── integration/ # Command workflow tests
│ └── workflow.bats
├── golden/ # Output format tests
│ └── output.bats
└── fixtures/ # Test data
└── setup.bash
tests/
├── test_layer0/ # Foundation tests
│ ├── test_exit_codes.py
│ ├── test_colors.py
│ └── test_constants.py
├── test_layer1/ # Basic helper tests
│ ├── test_logging.py
│ ├── test_error_json.py
│ ├── test_config.py
│ └── test_file_ops.py
├── test_layer2/ # Business logic tests
│ ├── test_validation.py
│ └── test_task_ops.py
├── test_layer3/ # Orchestration tests
│ ├── test_migrate.py
│ ├── test_hierarchy_unified.py
│ └── test_doctor.py
├── conftest.py # Shared fixtures
└── pytest.ini # pytest configuration
# Extract all function definitions from lib/
grep -rn '^[[:space:]]*[a-z_][a-z0-9_]*()' lib/*.sh | \
sed 's/().*//' | \
sed 's/.*://' | \
sort -u
# Extract function definitions from lib/layer*
grep -rn "^def \|^ def " lib/layer*/*.py | \
sed 's/def //' | \
sed 's/(.*$//' | \
sort -u
# Extract class definitions
grep -rn "^class " lib/layer*/*.py | \
sed 's/class //' | \
sed 's/(.*$//' | \
sort -u
For each function:
For each function/class:
test_*) that exercise the codepytest --cov=lib --cov-report=term-missing for precise coverageFunctions without test coverage:
| Coverage Type | Description | Priority |
|---|---|---|
| No coverage | Function never tested | Critical |
| Happy path only | Only success cases | High |
| No negative tests | No error cases | Medium |
| No edge cases | No boundary tests | Low |
# Test Coverage Report
## Summary
- **Total Functions**: {N}
- **Tested Functions**: {N}
- **Coverage**: {X}%
- **Critical Gaps**: {N}
## Coverage by File
| File | Functions | Tested | Coverage |
|------|-----------|--------|----------|
| lib/validation.sh | 15 | 12 | 80% |
| lib/task-ops.sh | 22 | 18 | 82% |
| lib/file-ops.sh | 8 | 3 | 38% |
## Untested Functions (Critical)
| Function | File | Risk | Recommended Test |
|----------|------|------|------------------|
| `atomic_write` | file-ops.sh | High | Unit test with failure scenarios |
| `validate_schema` | validation.sh | High | Integration test with invalid data |
## Partially Tested (Needs Improvement)
| Function | File | Missing |
|----------|------|---------|
| `add_task` | task-ops.sh | Error paths, edge cases |
| `update_status` | task-ops.sh | Invalid status values |
## Test Quality Issues
### Missing Negative Tests
- `validate_task_id` - No test for invalid format
- `parse_json` - No test for malformed input
### Missing Edge Cases
- `get_task_by_id` - No test for empty todo.json
- `list_tasks` - No test for >1000 tasks
## Generated Test Stubs
See: `{{OUTPUT_DIR}}/generated-tests/`
#!/usr/bin/env bash
# Tests for {{FUNCTION_NAME}}
# Generated: {{DATE}}
load '../fixtures/setup.bash'
setup() {
setup_test_environment
}
teardown() {
teardown_test_environment
}
# Happy path
@test "{{FUNCTION_NAME}} should {{EXPECTED_BEHAVIOR}}" {
# Arrange
{{SETUP_CODE}}
# Act
run {{FUNCTION_NAME}} {{ARGS}}
# Assert
assert_success
assert_output --partial "{{EXPECTED_OUTPUT}}"
}
# Error case
@test "{{FUNCTION_NAME}} should fail with {{ERROR_CONDITION}}" {
# Arrange
{{ERROR_SETUP}}
# Act
run {{FUNCTION_NAME}} {{ERROR_ARGS}}
# Assert
assert_failure
assert_output --partial "{{ERROR_MESSAGE}}"
}
# Edge case
@test "{{FUNCTION_NAME}} should handle {{EDGE_CASE}}" {
# Arrange
{{EDGE_SETUP}}
# Act
run {{FUNCTION_NAME}} {{EDGE_ARGS}}
# Assert
{{EDGE_ASSERTIONS}}
}
"""Tests for {{MODULE_NAME}}.{{FUNCTION_NAME}}
Generated: {{DATE}}
"""
import pytest
from lib.layer{{N}}.{{MODULE_NAME}} import {{FUNCTION_NAME}}
class Test{{FUNCTION_NAME_CAMEL}}:
"""Tests for {{FUNCTION_NAME}} function."""
# Happy path
def test_{{FUNCTION_NAME}}_success(self):
"""{{FUNCTION_NAME}} should {{EXPECTED_BEHAVIOR}}."""
# Arrange
{{SETUP_CODE}}
# Act
result = {{FUNCTION_NAME}}({{ARGS}})
# Assert
assert result == {{EXPECTED_OUTPUT}}
# Error case
def test_{{FUNCTION_NAME}}_fails_with_{{ERROR_CONDITION}}(self):
"""{{FUNCTION_NAME}} should fail with {{ERROR_CONDITION}}."""
# Arrange
{{ERROR_SETUP}}
# Act & Assert
with pytest.raises({{EXCEPTION_TYPE}}):
{{FUNCTION_NAME}}({{ERROR_ARGS}})
# Edge case
def test_{{FUNCTION_NAME}}_handles_{{EDGE_CASE}}(self):
"""{{FUNCTION_NAME}} should handle {{EDGE_CASE}}."""
# Arrange
{{EDGE_SETUP}}
# Act
result = {{FUNCTION_NAME}}({{EDGE_ARGS}})
# Assert
{{EDGE_ASSERTIONS}}
# Fixtures (if needed)
@pytest.fixture
def {{FIXTURE_NAME}}():
"""{{FIXTURE_DESCRIPTION}}"""
return {{FIXTURE_VALUE}}
# Run pytest with coverage for all lib layers
pytest --cov=lib --cov-report=term-missing tests/
# Coverage for specific layer
pytest --cov=lib.layer1 --cov-report=html tests/test_layer1/
# Generate coverage report by layer
pytest --cov=lib.layer0 --cov=lib.layer1 --cov=lib.layer2 --cov=lib.layer3 \
--cov-report=term-missing --cov-report=html:coverage_html tests/
@_shared/templates/skill-boilerplate.md#task-integration
{{OUTPUT_DIR}}/{{DATE}}_{{SLUG}}.md{{OUTPUT_DIR}}/generated-tests/@_shared/templates/skill-boilerplate.md#subagent-protocol
Test stubs MUST be written to: {{OUTPUT_DIR}}/generated-tests/*.bats
@_shared/templates/skill-boilerplate.md#manifest-entry
| Token | Description | Example |
|---|---|---|
{{TARGET_DIR}} | Source directory | lib/ |
{{TEST_DIR}} | Test directory | tests/ |
{{MIN_COVERAGE}} | Coverage threshold | 80 |
{{SLUG}} | URL-safe topic name | test-coverage |
| Function Type | No Tests | Happy Only | Full |
|---|---|---|---|
| Validation | Critical | High | OK |
| File I/O | Critical | High | OK |
| Data Transform | High | Medium | OK |
| Display/Format | Medium | Low | OK |
@_shared/templates/anti-patterns.md#testing-anti-patterns
| Pattern | Problem | Solution |
|---|---|---|
| 100% coverage goal | Tests for trivial code | Focus on critical paths |
| Only unit tests | Integration gaps | Balance unit/integration |
| Mocking everything | Tests don't reflect reality | Use fixtures where possible |
| Flaky tests | Non-deterministic failures | Fix timing, use stable fixtures |
@_shared/templates/skill-boilerplate.md#error-handling
@_shared/templates/skill-boilerplate.md#completion-checklist
@_shared/protocols/skill-chain-contracts.md
| Output | Format | Description |
|---|---|---|
gaps-list | JSON array | Prioritized list of untested functions |
test-stubs | Source files | Generated test file skeletons |
coverage-report | Markdown | Coverage analysis with metrics |
| Input | From Skill | Description |
|---|---|---|
metrics | codebase-stats | File complexity for prioritization |
hotspots | codebase-stats | High-change files need more tests |
| Direction | Skills | Pattern |
|---|---|---|
| Chains from | codebase-stats | producer-consumer |
| Chains to | test-writer-pytest | analyzer-executor |
The test-gap-analyzer identifies what tests are needed; test-writer-pytest creates the actual tests.