agentleFS
reddygopalkrishnareddygopalkrishna/developer-agent-skills/skills/unit-testing/SKILL.md

unit-testing

Skill8 starsChanged 9 days agoMITView on GitHub

Writes and updates unit tests for new or changed code in the project's existing framework and style, covering happy, error and boundary paths, then runs them with coverage and fixes failures. Use when implementing a feature or bug fix that needs tests, when asked to add or update unit tests or improve coverage for specific code, or when unit tests fail after a change. Not for choosing between test levels or fixing flaky tests (use test-strategy).

20 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use contract-testing, e2e-testing and 1 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • petrkindlmannSkill

    contract-testing

    Implement consumer-driven contract testing with Pact-JS (v16). Covers consumer test writing, broker-driven provider verification, Pact Broker setup, can-i-deploy as a deployment gate, webhook-triggered verification, pending pacts, and schema-first vs consumer-first approaches (OpenAPI/Ajv, Schemathesis). Use when: "contract test," "Pact," "consumer-driven," "API contract," "provider verification," "can-i-deploy." Not for: stubbing or mocking a dependency to isolate a test — use service-virtualization; general REST/GraphQL endpoint assertions against your own API — use api-testing. Related: api-testing, service-virtualization, ci-cd-integration, test-environments.

    Also in 3 projects that use this

  • etewiahSkill

    e2e-testing

    Playwright E2E testing and Lighthouse performance auditing. Use when setting up E2E tests, running Playwright tests, performing Lighthouse audits, or debugging E2E test failures.

    Also in 4 projects that use this

  • Microsoft AzureSkill

    release-readiness

    Complete ODIN release documentation and validation checks before declaring user-visible work complete, preparing a release, or opening the Release-to-main pull request.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. 0 are common, 12 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 17 edited versions we read keep these.

  • 12

    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
  1. Distinctive:

    Every behavior you added or changed gets a unit test that would fail if that behavior broke.

    line 9
  2. Distinctive:

    Not for: deciding unit vs integration vs end-to-end, test doubles across a whole system, or flaky tests.

    line 17
  3. Distinctive:

    Detect the framework and conventions: Look for config and existing tests:

    line 21
  4. Distinctive:

    Hand off to verification: Run the full project checks with the verify-before-done skill before reporting.

    line 39
  5. Very specific:

    If the project already has a coverage script (for example npm run test:coverage), use it instead.

    line 54
  6. Distinctive:

    Use the report to find untested behavior: an error branch with no test, a boundary never hit.

    line 58
  7. Distinctive:

    Never write a test only to execute lines.

    line 59
  8. Distinctive:

    Don't lower a project's coverage threshold to make CI pass.

    line 60
  9. Distinctive:

    When a unit test fails after a change, decide which side is wrong before touching anything:

    line 90
  10. Distinctive:

    Never delete, skip or loosen a failing test just to get green.

    line 100
  11. Distinctive:

    Testing private methods directly: Test through the public interface.

    line 104
  12. Distinctive:

    Tests written after the fact that only pass: never seen failing, so never proven.

    line 111
  13. Distinctive:

    Every added or changed behavior has a test, including its error and boundary cases.

    line 115

“Common” is measured: kept by at least 6 in 10 of the 17 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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Unit Testing

Every behavior you added or changed gets a unit test that would fail if that behavior broke. Test through the unit's public interface, match the tests already in the project, and treat coverage as a map of what you missed, never as the goal.

When to use

  • You wrote or changed a function, class, module or component and it needs tests.
  • The user asks to add unit tests or raise coverage for specific code.
  • Unit tests fail after a change and you must decide whether the code or the test is wrong.

Not for: deciding unit vs integration vs end-to-end, test doubles across a whole system, or flaky tests. Use the test-strategy skill for those. When you finish, run the verify-before-done skill.

Workflow

  1. Detect the framework and conventions. Look for config and existing tests:
    • JS/TS: vitest.config.*, jest.config.*, "test" in package.json, *.test.ts / *.spec.ts.
    • Python: pytest.ini, [tool.pytest.ini_options] in pyproject.toml, conftest.py, test_*.py.
    • Go: *_test.go next to the code.
    • Java/Kotlin: src/test/java, JUnit 5 or Kotest dependencies.
    • C#: *.Tests.csproj with xUnit, NUnit or MSTest.
    • Rust: #[cfg(test)] mod tests in the file, or tests/. Open the tests nearest to the code you changed. Copy their file location, naming, fixtures, factories, helpers and assertion style. Never add a second test framework.
  2. List what changed. From the diff, write down each public function or method you added or changed, and each new branch, error path and edge case in it.
  3. Write the case list before the tests. For each unit:
    • Happy path: typical valid input gives the expected output or effect.
    • Error paths: invalid input, thrown exceptions, rejected promises, error return values, failed dependencies.
    • Boundaries: empty, one, many; zero, negative, min/max; exactly at a limit and one past it; null / undefined / None; empty string, whitespace, Unicode; duplicates; date and time edges (month end, leap day, time zones).
    • State: each state transition, and calling things twice or out of order.
  4. Write the tests. One behavior per test. Name it after the behavior (rejects_expired_coupon, "returns 0 for an empty cart"). Use Arrange-Act-Assert. Use table-driven tests for many input/output pairs (example below). Assert on outputs and visible effects, not on which private helpers were called.
  5. Keep them deterministic and fast. Inject or fake the clock, random numbers, UUIDs and environment. No network, real database, file system or sleeps in unit tests; fake only those I/O boundaries and leave the logic under test real.
  6. Prove each new test can fail. Break the code briefly (flip a condition, return a wrong value) or invert the expectation, watch the test fail with a clear message, then revert. A test you never saw fail may be testing nothing.
  7. Run the new tests, then the whole unit suite with coverage (commands below). Look at uncovered lines in the files you changed. Add tests for uncovered behavior that matters. Leave trivial code (getters, generated code, framework glue) alone.
  8. Hand off to verification. Run the full project checks with the verify-before-done skill before reporting.

Running with coverage

StackCommandNeeds
Vitestnpx vitest run --coveragea coverage provider package, such as @vitest/coverage-v8
Jestnpx jest --coveragebuilt in
pytestpytest --cov=<package> --cov-report=term-missingpytest-cov
Gogo test -coverprofile=cover.out ./... then go tool cover -func=cover.outbuilt in
Mavenmvn test jacoco:report (report in target/site/jacoco/)jacoco-maven-plugin configured with prepare-agent
Gradle./gradlew test jacocoTestReportthe jacoco plugin applied
.NETdotnet test --collect:"XPlat Code Coverage"the coverlet.collector package in the test project
Rustcargo llvm-covthe cargo-llvm-cov tool installed

If the project already has a coverage script (for example npm run test:coverage), use it instead. Adding a coverage package or tool changes the project, so ask the user first.

Coverage is a signal, not a target

  • Use the report to find untested behavior: an error branch with no test, a boundary never hit.
  • Never write a test only to execute lines. A test with no meaningful assertion raises coverage and catches nothing.
  • Don't lower a project's coverage threshold to make CI pass. Don't add exclusions to hide your own new code.
  • High coverage with weak assertions is worse than lower coverage with strong ones, because it looks safe.

Table-driven example

The same pattern exists in every framework (it.each / test.each, @pytest.mark.parametrize, Go table tests, JUnit @ParameterizedTest, xUnit [Theory]).

import pytest
from shop.pricing import discount_for

@pytest.mark.parametrize(
    "total, expected",
    [
        (0, 0),          # empty cart
        (99.99, 0),      # just below threshold
        (100, 10),       # exactly at threshold
        (250, 25),       # typical
    ],
)
def test_discount_for_totals(total, expected):
    assert discount_for(total) == expected

def test_discount_rejects_negative_total():
    with pytest.raises(ValueError, match="negative"):
        discount_for(-1)

Fixing failing tests

When a unit test fails after a change, decide which side is wrong before touching anything:

SituationAction
The behavior changed on purpose (new requirement)Update the test to the new behavior, and say so in your report
The behavior changed by accidentFix the code; leave the test as it is
The test relied on internals that were refactoredRewrite the test against the public behavior
A snapshot changedRead the diff line by line; update only if every change is intended
You can't tell which is rightStop and ask the user, showing the old and new behavior

Never delete, skip or loosen a failing test just to get green.

Anti-patterns

  • Testing private methods directly. Test through the public interface; if a private part needs its own tests, it may deserve its own unit.
  • Mocking the thing under test, or mocking so much that the test only checks the mocks.
  • Asserting call sequences (expect(helper).toHaveBeenCalledTimes(3)) instead of results.
  • Tautological tests that recompute the expected value with the same logic as the code.
  • One giant test covering ten behaviors; when it fails you don't know which one broke.
  • Snapshot everything and approve every snapshot update without reading it.
  • Sleeps and real time in unit tests.
  • Tests written after the fact that only pass: never seen failing, so never proven.

Done when

  • Every added or changed behavior has a test, including its error and boundary cases.
  • Each new test was seen failing once for the right reason.
  • New tests follow the existing framework, layout and style.
  • The unit suite passes; coverage of the changed files was reviewed, and gaps that matter are tested.
  • Any test you changed is listed in your report with the reason.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.