Testing
Skill felixhennequin-gif/claude-code-config-template/cli/template-files/claude/skills/core/testing
Testing strategy and conventions. Activates when writing tests, deciding what to test, editing files under *.test.*, *.spec.*, tests/, or __tests__/, setting up a test suite, or evaluating test coverage for any language or stack.From its SKILL.md
npx -y skills add felixhennequin-gif/claude-code-config-template --skill testingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 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.
SKILL.md
6.0 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Testing
The code snippets below use JavaScript/Jest syntax as a concrete example, but every rule is language-agnostic. Apply the same principles with
pytest,go test,cargo test,phpunit, etc. A Python equivalent of each example is shown inline where the shape differs enough to matter.
1. Decide what to test first
Value hierarchy (highest to lowest ROI):
- Integration tests against real dependencies (DB, HTTP) — catch the bugs that matter in prod
- Unit tests for pure business logic with complex branching
- Do not test framework glue, getters/setters, or generated code
Rule of thumb: if a test requires mocking 3+ dependencies to run, you're testing the wrong layer. Move the test up (integration) or extract the logic into a pure function and test that.
// BAD — mocks everything, tests nothing real
it('should call prisma.user.findUnique', async () => {
prisma.user.findUnique.mockResolvedValue({ id: '1', email: '[email protected]' });
const result = await getUser('1');
expect(prisma.user.findUnique).toHaveBeenCalledWith({ where: { id: '1' } });
});
// GOOD — tests the behavior, not the implementation
it('should return null when user does not exist', async () => {
const result = await getUser('nonexistent-id');
expect(result).toBeNull();
});
2. Define the success criterion before implementing
Not dogmatic TDD — just: know what "done" looks like before writing code. Write the test name (or assertion) first, even if the test body comes later.
// BAD — implement first, test whatever comes out
function applyDiscount(price, code) { /* ... */ }
// test written after: mirrors implementation, not the requirement
// GOOD — define the contract first
it('should apply 20% discount for code SUMMER20')
it('should return original price for unknown codes')
it('should throw for negative prices')
// now implement applyDiscount to make these pass
3. Coverage: 70% is the floor, prod-failing cases are the goal
70% line coverage on business logic is the floor — below that, flag it. But hitting the floor is not the point: 100% coverage does not mean the code is correct, it only means every line was executed at least once. The actual goal is that every case which fails in prod is covered by a test. A suite at 100% with no edge-case assertions is also a failure.
Mandatory cases for any non-trivial function:
- Happy path (expected input, expected output)
- Edge cases: null/undefined, empty string/array, zero, boundary values
- Error cases: invalid input, dependency failure, permission denied
// For a function that parses a user age:
it('should parse valid age') // happy path
it('should throw for negative age') // edge case
it('should throw for non-integer age') // edge case
it('should throw for age over 150') // boundary
# Same function, pytest equivalent — same coverage shape, different syntax:
def test_parses_valid_age(): ...
def test_raises_for_negative_age(): ...
def test_raises_for_non_integer_age(): ...
def test_raises_for_age_over_150(): ...
4. Framework, structure, naming
- Framework — use the project's existing test runner. Don't switch frameworks without asking. Check
package.jsonscripts,Makefile,pyproject.toml, or CI config for the correct test command. If no test infrastructure exists, ask the user which framework to use before creating test files. - Structure — test files colocated next to source OR in a
tests/directory. Pick one per project and stay consistent. - File name —
[module].test.js/[module].spec.js— adapt the extension to the project language (.test.ts,test_module.py,_test.go, etc.). - Grouping — group with
describe()(or the equivalent in your framework) by function/method; nest for variants.
Naming tests by behavior, not implementation
// GOOD — describes the expected behavior
it('should return 401 when token is expired')
it('should create an item and return 201')
// BAD — describes the implementation
it('calls prisma.item.create')
it('works correctly')
AAA pattern (Arrange → Act → Assert)
it('should return the item by id', async () => {
// Arrange
const item = await createTestItem();
// Act
const res = await request(app).get(`/api/items/${item.id}`);
// Assert
expect(res.status).toBe(200);
expect(res.body.name).toBe(item.name);
});
Test isolation
- Each test is independent — no shared mutable state between tests.
- Use
beforeEachfor setup,afterEachfor cleanup. - Database tests: use transactions that roll back, or truncate tables between tests.
5. When NOT to write tests
Skip tests for:
- One-shot migration scripts (run once, delete)
- Generated code (Prisma client, GraphQL types, OpenAPI stubs)
- Pure configuration files
- Trivial getters/setters with no logic
Do not let "we should have tests" become a reason to write tests that test nothing. A bad test is worse than no test — it gives false confidence and breaks on every refactor.
Anti-patterns
- ❌ Mocking everything — if you mock the DB, you're not testing the query
- ❌ Testing implementation details (which function was called, in what order)
- ❌ Snapshot tests on dynamic data — they always go stale
- ❌
test.skipleft indefinitely — fix it or delete it - ❌ One giant test that asserts 15 things — split into focused tests
- ❌ Testing the framework ("does express call next()?") — it does, trust it
Helper scripts
scripts/coverage-check.sh <min-percent>— reads coverage output from stdin (Istanbul/c8, pytest-cov, or go cover format), exits non-zero if below the threshold. Pipe your coverage command into it:npm test -- --coverage | scripts/coverage-check.sh 80. Makes the "coverage is a floor" rule enforceable in CI.
What ships with it: 1 file
1.9 KB alongside SKILL.md, 1 of them executable
scripts/
- coverage-check.shruns1.9 KB
Gives 0 of the 12 instructions most test skills give in ~1.4k tokens
Counted across 964 of the 1,571 authors here whose files we hold, read 2026-08-07
- Close the browser when donein 55 of 964, across 12 files
- Wait for network idle statein 51 of 964, across 6 files
- Launch Chromium in headless modein 49 of 964, across 6 files
- Use descriptive selectors for elementsin 49 of 964, across 6 files
- Run provided scripts with help flag firstin 49 of 964, across 6 files
- Add appropriate explicit waitsin 48 of 964, across 5 files
- Use bundled scripts as black boxesin 46 of 964, across 3 files
- Do not read script source codein 46 of 964, across 3 files
- Use sync playwright for scriptsin 46 of 964, across 3 files
- Inspect dom before executing actionsin 46 of 964, across 3 files
- Run the full test suitein 37 of 964
- Write the failing test firstin 29 of 964, across 23 files
Said here and by no other author read
- extract pure functions instead of mocking heavily
- maintain at least 70 percent line coverage on business logic
- use transactions or truncate tables between database tests
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.