Skip to content
Back to skills

Testing Best Practices

ASecurity

Use when choosing a verifier, running a feature on its closest-to-live surface, capturing UI evidence, deciding whether a check becomes a permanent test, diagnosing an unreliable test, or designing nontrivial regression coverage; routine execution of an established check needs no extra workflow.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentsgotestinggit

Security analysis

A100/100

Scanned October 16, 2026

npx -y skills add alleneubank/agent-profile --skill testing-best-practices --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Testing Best Practices?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Testing Best Practices
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/alleneubank-testing-best-practices/badge)](https://www.skillsdirectory.com/skills/alleneubank-testing-best-practices)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: testing-best-practices
description: Use when choosing a verifier, running a feature on its closest-to-live surface, capturing UI evidence, deciding whether a check becomes a permanent test, diagnosing an unreliable test, or designing nontrivial regression coverage; routine execution of an established check needs no extra workflow.
---

# Verification

Start with the requested behavior and the important ways it could fail. Use
existing test commands and the smallest boundary that can expose those failures.
For an assembled-behavior bug, try the public path early; for isolated logic,
a focused example or property test may be sufficient. Record reproduction
limits rather than claiming an unobserved failure.

## Choosing evidence

- Check effects, not proxies: persistence needs a fresh read; delivery needs the
  destination's result; startup or a screenshot cannot establish either.
- Take every expected result from an oracle independent of the code under
  test: the user story, a spec, a published contract, the real system, or a
  property, or a simpler reference implementation. A **tautological test**
  derives its expectation from the code it checks (the same formula, a
  production helper the code also calls, or its output pasted back unchecked), so
  it shares that code's faults. Write the literal you worked out. Sharing a
  helper is fine when its own tests own its exact output and this test only
  checks that its result appears.
- Prefer real dependencies, then behaviorally conformant fakes. A mock of a
  boundary you own may isolate the unit under test for speed; it checks that
  unit, not what it replaced, which needs its own run against the real thing.
  Do not build a simulated third-party contract to prove the same simulation.
- Keep tests understandable: name the scenario, make important inputs explicit,
  and use discriminating expected results. Assert call order only when that
  interaction is itself the promised behavior.
- Unit tests, TDD, integration tests, and exploratory use are alternatives or
  complements selected by risk, not a checklist of layers. A property held by
  types needs no test of its own.

## User-facing work

- Use the repository's surface ladder (each surface, what it can show, where it
  runs), or record the one you used. Name what the highest drivable surface
  cannot qualify (real biometrics, signed bytes, push delivery, production
  data); only that waits for the human or device gate. A finding that "needs
  real-environment evidence" gets the cheapest executable probe now.
- Captures walk each changed interaction, not first paint: production today,
  then the change, in each state it touches (empty, error, loading, larger
  text, dark). They go in the change record, never committed, and show
  visible state only.

## Evidence or permanent test

Once the change is verified, decide what outlives it. Probes, one-off scripts,
screenshots, traces, and exploratory runs are evidence: record what they showed
(command and result) with the change — its review, task, or PR — and discard
them.
Every permanent test is loaded, run, and maintained by each later change, so it
earns that cost by guarding one of:

- a user-visible or published contract, at the level its user relies on it;
- isolated logic whose failures are cheap to state and expensive to reach end
  to end — money, parsing, state machines, invariants; its cases are the
  failures stated from the spec;
- a defect that shipped. It gets one regression check at the smallest level
  that reproduces what the user observed, seen failing before the fix. A
  mistake introduced and fixed within the same task shipped nothing: nothing is
  added because of it and no comment narrates it; if the unit earns a test, its
  boundaries are cases like any other.

A **change detector** grades the implementation rather than the outcome: it
asserts calls on a collaborator you own when the call is not the promised
behavior, renders under stubbed UI to read props, compares constants or
fixtures to themselves, or grades a third-party library's behavior instead of
yours. It reddens on behavior-preserving change and passes real defects. Do not
write one. When your change must edit one or reddens one, delete it; replace it
only if what it stood in for meets the bar above, and say in the change record
what is left unproven.

## Reliable execution

Give concurrent runs their own state. Control clocks, randomness, environment,
and dependency versions where they affect repeatability. Wait for observable
conditions with deadlines; never use elapsed sleep as proof of success. Avoid
runtime test backdoors; explicit dependency injection is legitimate.

If a check fails, locate the cause before attributing it to the environment or
a flake. When the public path is the verifier, its environment is part of it:
a stale server or broken fixture yields a verdict about the environment, not
the change. Repair it or report the check blocked; a narrower test that cannot
reach the failure is no substitute. Reproduce claimed pre-existing failures at the baseline. A retry is
a diagnostic probe, not evidence of correctness; stop repeated structural
failure and report the block. Inspect progress before killing a slow run.

Record which inputs a result covered: reuse it while they are unchanged, and
not after they change. A new commit id, message, or squash alone does not
invalidate it. After changes, rerun only the affected checks. A required check
that cannot execute remains blocked, never replaced by static confidence.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.