Agent skill
buff-test
This skill should be used when the user asks to "write tests", "generate tests", "add tests", "test this feature", "run /buff:test", "create unit tests", "create integration tests", "check test coverage", "show coverage", "find untested code", "test changed files", "--coverage", "--gaps", "--changed", "coverage tracking", "change-aware", or any request involving test creation or testing workflows.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/test-betheer-buff
SKILL.md
buff-test v2
Coverage-aware smart testing with change-aware selection and context-informed generation. Uses the project dependency graph to track what's tested, what's not, and what needs retesting when code changes — then generates tests informed by real caller data, past corrections, and known edge cases.
Framework detection
Detect in this order (stop at first match):
| File | Framework |
|---|---|
vitest.config.* |
Vitest |
jest.config.* |
Jest |
pytest.ini / pyproject.toml with [tool.pytest] |
pytest |
Cargo.toml with [dev-dependencies] test crates |
Rust built-in |
*_test.go files present |
Go built-in |
bun.lockb and no config |
Default to Vitest |
package.json only |
Default to Vitest |
requirements.txt only |
Default to pytest |
After detection, write to .buff/memory/context.json:
{ "test_framework": "vitest" }
On subsequent runs, read from context.json and skip detection.
Coverage tracking via graph
Uses .buff/memory/graph.json for a live coverage map — no external coverage tools required.
Function-level coverage check:
- Read the target file's entry in
graph.jsonto get itsexportslist - If a
test_fileis mapped, Grep the test file for references to each exported symbol - Mark each export as tested (referenced in test file) or untested (not referenced)
- Update the file's
coveragefield ingraph.json:
{
"coverage": {
"functions": 3,
"tested": 2,
"untested": ["createSession"]
}
}
This runs automatically after test generation and can be triggered manually with --coverage.
Scope handling
| Invocation | Scope |
|---|---|
/buff:test |
Test the last modified file |
/buff:test src/auth.ts |
Test the specified file |
/buff:test --coverage |
Show project coverage map |
/buff:test --gaps |
Untested exports ranked by risk |
/buff:test --changed |
Test only changed files + dependents |
/buff:test --run |
Generate and immediately run |
--coverage output
Read .buff/memory/graph.json — for each file entry, extract only exports, coverage, and imported_by count (skip imports_from, lines, last_modified to save tokens). Compute coverage from the coverage field. Display:
## Test Coverage — project-wide
| File | Exports | Tested | Gap | Risk |
|---|---|---|---|---|
| src/auth.ts | 3 | 2 (67%) | createSession | HIGH — 3 dependents |
| src/db.ts | 4 | 1 (25%) | connect, query, close | HIGH — foundation |
| src/utils.ts | 8 | 6 (75%) | formatDate, retry | LOW — leaf |
Overall: 20/28 exports tested (71%)
Critical gaps: 2 files below 50% with dependents
Risk is determined by imported_by count in graph.json:
- HIGH — 3+ dependents, or 0 dependents but is imported by HIGH-risk files (foundation module)
- MEDIUM — 1-2 dependents
- LOW — 0 dependents (leaf module)
Files with no imported_by entries and no dependents are leaf modules. Files imported by many others are foundation modules — untested foundation code is always HIGH risk.
--gaps risk ranking
Read graph.json — extract only exports, coverage.untested, and imported_by count per file. Collect all untested exports across the project. Rank by risk — number of dependents from the imported_by field determines priority.
Risk formula: Untested export in a foundation module (many dependents) > untested export in a mid-tier module > untested export in a leaf utility.
Output a ranked list with risk justification:
## Untested Exports — ranked by risk
1. src/db.ts → connect, query, close
Risk: CRITICAL — foundation module, 6 dependents, 25% coverage
Dependents: auth.ts, users.ts, posts.ts, comments.ts, admin.ts, migrations.ts
2. src/auth.ts → createSession
Risk: HIGH — 3 dependents, 67% coverage
Dependents: router.ts, middleware.ts, admin.ts
3. src/utils.ts → formatDate, retry
Risk: LOW — leaf module, 0 dependents, 75% coverage
Action: Run `/buff:test src/db.ts` to address the highest-risk gap.
--changed workflow
Change-aware test selection — run only what's affected by recent changes.
Steps:
- Run
git diff --name-onlyto get changed files (staged + unstaged) - For each changed file, look up its
test_filefromgraph.json - For each changed file, look up its
imported_byfromgraph.jsonto find dependents - For each dependent, look up its
test_filefromgraph.json - Deduplicate the test file list
- Run only the affected test files
Example output:
Changed: src/auth.ts
Direct test: src/auth.test.ts
Dependents: src/router.ts, src/middleware.ts
Dependent tests: src/router.test.ts, src/middleware.test.ts
Running 3 test files (skipping 8 unchanged)
If a changed file has no test_file mapping in graph.json, flag it:
⚠ src/newfile.ts has no test file. Run `/buff:test src/newfile.ts` to generate one.
Counterfeit context loading
Before generating any tests, load context from counterfeit memory to inform generation:
.buff/memory/graph.json— read the target file's entry: what calls this function (imported_by), what it depends on (imports_from), existing coverage gaps (coverage.untested)~/.buff/memory/corrections.json— check for past test-related corrections (entries whereskill: "test"). Apply these to avoid repeating mistakes..buff/memory/learnings.json— check for project-specific test learnings (edge cases, patterns that apply to this code type)~/.buff/memory/patterns.json— check for error handling patterns (error_handling: "result-pattern"→ assert on Result types) and test conventions (e.g., no mocks for DB)- Caller files — for each file in
imported_by, Grep for import lines referencing the target module and the call sites using the exported symbols. Extract only the import lines and call-site lines — do NOT read full caller files. This reveals real-world usage patterns.
Smarter test generation
Context from counterfeit changes what tests get generated:
-
Caller-informed inputs: Testing
validateToken()? Graph shows it's called frommiddleware.tswithreq.headers.authorization. Generate tests using real header formats (Bearer xyz, missing header, malformed token) instead of generic placeholder strings. -
Correction-aware approach:
corrections.jsonhas an entry saying "no mocks for repository tests"? Generate integration tests with real database calls instead of mocked ones. -
Pattern-aware assertions:
patterns.jsonshowserror_handling: "result-pattern"? Generate tests that assert onResulttypes (isOk(),isErr()) instead of try/catch. -
Learning-informed edge cases:
learnings.jsonsays "middleware order matters — auth before rate limiter"? Include ordering tests when generating middleware test suites.
If no counterfeit context exists (new project, empty memory), fall back to standard test generation — analyze the source file directly without caller context.
Test generation workflow
- Counterfeit context load — read graph.json, corrections.json, learnings.json for the target file
- Read target file — understand exports, functions, classes, error paths
- Check graph for callers — Grep caller files (from
imported_by) for import lines and call sites to understand how these functions are actually used - Generate tests with context — use real usage patterns from callers, known edge cases from learnings, and correction-informed approach
- Place test file following project conventions:
- If
__tests__/dir exists → place there - If
*.test.tspattern exists → colocate with source - If
tests/dir exists → place there - Default: colocate as
<filename>.test.<ext>
- If
- Offer to run (or auto-run with
--run)
Print: "Generated N tests in [filename]. Run now? [Y/n]"
Wait for user confirmation before running. Exception: if invoked with --run flag, execute immediately.
What makes a good buff test
Test behavior, not implementation:
// Good — tests what the function does
it('returns 401 when token is expired', async () => {
const res = await handler(expiredTokenRequest)
expect(res.status).toBe(401)
})
// Bad — tests implementation detail
it('calls validateToken function', () => {
expect(validateToken).toHaveBeenCalled()
})
One assertion per test (usually):
- Tests with 5+ assertions are testing multiple things — split them
- Exception: related data shape assertions can group (checking multiple fields of one object)
Descriptive names:
- Format:
[unit] [action/condition] [expected result] - Example:
parseDate with invalid string throws ParseError - Example:
createUser when email exists returns conflict error
No test interdependence:
- Each test runs in isolation
- No shared mutable state between tests
- Use
beforeEachto reset state, not shared variables
Output format
// Vitest / Jest example
import { describe, it, expect, beforeEach } from 'vitest'
import { [exports] } from './[source-file]'
describe('[unit under test]', () => {
beforeEach(() => {
// reset state
})
it('[action] [condition] [expected]', () => {
// arrange
// act
// assert
})
})
# pytest example
import pytest
from [module] import [exports]
class Test[Unit]:
def test_[action]_[condition]_[expected](self):
# arrange
# act
# assert
Running tests
If user confirms (or --run flag is set):
# Vitest
bunx vitest run [test-file]
# Jest
npx jest [test-file]
# pytest
python -m pytest [test-file] -v
# Rust
cargo test [test-name]
# Go
go test ./... -run [TestName]
Report results inline:
Tests: 12 passed · 0 failed · 2 skipped
Coverage: [if available]
If tests fail, diagnose immediately — do not just show the error. Identify whether the test is wrong or the implementation is wrong.
Writes to counterfeit
After test generation and execution, update counterfeit memory:
- Coverage data →
.buff/memory/graph.json: Settest_filemapping for the target file. Updatecoveragefield with function count, tested count, and untested list. - Test results →
.buff/memory/learnings.json: If tests revealed edge cases or unexpected behavior, record as a learning. Example:{"learning": "validateToken silently returns null on empty string", "source": "test discovery", "applies_to": "src/auth.ts"}. - Test patterns →
~/.buff/memory/patterns.json: If the test approach used a pattern not yet recorded (e.g., integration tests for repositories), update thearchitecturearray with the pattern.
Graph update (post-skill)
After generating tests, update graph.json for the tested file:
- Set
test_fileto the path of the generated test file - Grep the test file for references to each export in the source file
- Update
coverage.functionsto the total number of exports - Update
coverage.testedto the count of exports referenced in the test file - Update
coverage.untestedto the list of exports NOT referenced in the test file - Update
updated_attimestamp
Correction detection
Watch for the user correcting test output (rejection, replacement, redirect, style correction). Follow the correction capture mechanism defined in counterfeit SKILL.md — detect signals, record to learnings.json + corrections.json, promote to patterns.json at 2+ occurrences. Use skill: "test" when writing correction entries.
Forge mode
In /buff:auto (forge), run tests automatically after code generation without asking. Report pass/fail inline and continue the loop. If tests fail in forge mode, fix them before proceeding to validation.
In forge mode, use --changed logic for minimum test set: only run tests affected by the files changed in the current forge cycle, rather than the full test suite. This keeps forge loops fast on large projects.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?