Generate tests for code that already exists. Use when a module has no tests, coverage is thin, a fix needs a regression test, or a change should land with proof it still works. Auto-triggers on: "write tests for", "add test coverage", "this needs tests"
Installs into .claude/skills of the current project.
Are you the author of Write Test?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/univers42-write-test)
---
name: write-test
description: >
Generate tests for code that already exists. Use when a module has no tests,
coverage is thin, a fix needs a regression test, or a change should land with
proof it still works. Auto-triggers on: "write tests for", "add test coverage",
"this needs tests"
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
metadata:
stage: beta
since: "1.0.0"
---
# Write Tests
## 0. Detect the framework
- Run `devil facts` — it reports the detected test framework. Write in
THAT framework, in its idiom (see `rules/test-frameworks.md`, which a host that
installed the kit as a plugin has only after `devil setup`; the detection below
is the fact the step needs and does not depend on it).
- `rules/test-frameworks.md` names the idioms per stack. To detect, read the
project's own manifest (`package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`,
`build.gradle`, `pom.xml`) for a test dependency, then read the tests already in
the tree for the framework they import. The manifest alone is not proof: a
dependency can sit installed and unused, and the existing tests are what a new
one has to sit next to. Both agreeing, or one of them, is the answer.
- Write in THAT framework. Don't introduce a second framework; don't hand-roll
asserts/mocks it already ships.
- Nothing in the manifest and no tests in the tree? Pick the canonical default for
the stack and say why in one line.
## 1. Read the source
- Understand every public function's contract
- Identify edge cases from the implementation (not just happy path)
## 2. Design test cases (before writing any code)
For each function, list:
- Happy path (normal input → expected output)
- Boundary (empty, zero, max, nil/null)
- Error path (invalid input, resource failure)
- Concurrency (if the function touches shared state)
Present the test plan. Wait for approval.
## 3. Write
- Table-driven / parameterized tests in the detected framework's idiom (Go subtests, `rstest`, `it.each`, `pytest.mark.parametrize`)
- Property-based tests for anything parsing external input (Hypothesis, proptest, fast-check, `testing/quick`)
- One test function per behavior, not per source function
- Test names describe the scenario: `test_login_rejects_expired_token`
- No test depends on another test's state
- No sleep() — use channels, signals, or mocks
## 4. Verify
- All new tests pass
- All existing tests still pass
- No flaky tests (run 3 times)
- Report coverage delta
## Report
| Metric | Value |
|---|---|
| Framework detected | |
| Tests added (passing) | |
| Existing tests still green | |
| Coverage delta | |
| Behaviors still untested | |
Plus: the test command you ran and its output, any case you deliberately did not
cover and why, and anything the source does that you could not pin down from the
outside.