writing-unit-tests
Skill1 starsChanged 30 days agoMITView on GitHub
Use when writing unit tests for specific code — adding tests, improving coverage, or starting a TDD cycle. Triggers on "add tests", "write tests for X", or when modifying code that needs tests.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- jaktestowac/awesome-copilot-for-testerstheir own version, first seen Nov 1, 2026
- Asvarox/allkaraoketheir own version, first seen Oct 8, 2026
- mitchdenny/hex1btheir own version, first seen Oct 8, 2026
- TriliumNext/Triliumtheir own version, first seen Oct 8, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- TriliumNext/Trilium★ 39ksame name
- Asvarox/allkaraoke★ 269same name
- mitchdenny/hex1b★ 182same name
- jaktestowac/awesome-copilot-for-testers★ 118same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository11 other files it gives its agents.
- addressing-findingsSkill
- analyze-codeSkill
- brainstormSkill
- coding-disciplineSkill
- designing-interfacesSkill
- guiding-manual-testingSkill
- knowledge-baseSkill
- researchSkill
- style-checkerSkill
- test-driven-developmentSkill
- using-software-specialistsSkill
The file
We split this skill into the rules it gives an agent
2 rules. 0 are common, 1 is distinctive, and 1 is very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 46
Use // given / // when / // then comments only if the existing codebase uses them.
- Distinctive: line 56
If no reference exists for the project's language, apply the principles above and mirror existing project conventions.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Writing Unit Tests
A unit test asserts observable behavior, never implementation. Given state + input, verify output + side effects the caller can observe. If you're asserting call counts, internal fields, or private methods, step back.
For a detailed human-readable guide, see docs/how-to-write-unit-tests.md.
Steps
- Inspect existing tests — if the project instructions (CLAUDE.md, CLAUDE.local.md) name reference test files, those are the convention: read them first and follow them even when tests next to the code under test differ — neighbours may be legacy; mention the drift once. Without named references, read 2-3 nearby test files. Note naming, assertion library, mock framework, fixture patterns. Project conventions override the language reference.
- List scenarios — enumerate cases across the four quadrants. Present for confirmation before writing (skip if user says proceed).
- Read the language reference — pick the matching file from the dispatch table below.
- Write tests — one behavior per test. AAA structure. Run the full suite — never leave it red.
- Prove the assertions bite — for a test whose contract is a side effect on a mock (a rollback, a commit, a publish), break that side effect once in the code under test, confirm the test fails, restore it. A test that passes both ways asserts nothing.
Scenario Quadrants
| Quadrant | What to verify |
| Happy path | Valid inputs → expected successful output |
| Negative inputs | Nulls, empty, out-of-range, malformed — expect explicit errors or sentinel returns |
| Boundary conditions | 0, 1, off-by-one, max/min, overflow — bugs cluster here |
| Error paths | Dependency failures: DB down, network timeout, third-party error response |
FIRST-U
| Principle | Rule |
| Fast | Single-digit ms. No real I/O. |
| Isolated | No shared state. Tests run in any order. |
| Repeatable | No real clock, RNG, network, or filesystem. Pin time, seed randomness. |
| Self-validating | Explicit assertions. No manual inspection. |
| Timely | Write with the code, not months later. |
| Understandable | Name reads like a spec; body is short. A reader understands what's tested without reading the implementation. |
Structure: Arrange–Act–Assert
- Arrange — create unit under test, prepare inputs, configure doubles
- Act — exactly one call. Multiple calls = multiple behaviors; split.
- Assert — verify observable result and side effects
Use // given / // when / // then comments only if the existing codebase uses them.
Mock Rules
- Mock at boundaries — external APIs, databases, queues, filesystem, time, randomness
- Don't mock internals — value objects, DTOs, pure functions use real instances
- Mock your own port, not the third-party SDK — wrap external libraries behind an interface you control
Language References
If no reference exists for the project's language, apply the principles above and mirror existing project conventions.
| Reference | Stack |
| javascript_unit_test.md | Jest / Vitest |
| python_pytest_unit_test.md | pytest + monkeypatch / unittest.mock |
| java_unit_test.md | JUnit 5 + AssertJ + Mockito |
| go_std_unit_test.md | Go testing stdlib |
| go_testify_unit_test.md | Go + testify |
Common Mistakes
| Mistake | Fix |
| Asserting call counts when output would do | Assert return value; mock only when the side effect IS the behavior |
new Date(), Math.random(), real clock | Pin time, seed randomness — non-determinism breaks Repeatable |
| Mocking the third-party SDK directly | Wrap in a port you own, mock the port |
| Silently copying broken patterns from existing tests | Flag the anti-pattern to the user |
.Maybe() / optional expectations on the calls that are the contract | Register every call explicitly; a test that passes whether or not the rollback happened verifies nothing |
| Boolean flags in the table that the loop body turns into mock expectations | Put the expectations in the case (a prepareMock closure or equivalent) so the reader sees exactly which calls the scenario makes |
| Following the neighbouring tests when the project names reference files | The references win; neighbours may be legacy |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

