Skip to content
Back to skills

Writing Meaningful Tests

ASecurity

Use when writing or modifying tests, adding mocks, or tempted to add test-only methods to production code

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 6, 2026
ai-agentstypescriptrusttesting

Security analysis

A100/100

Scanned September 6, 2026

npx -y skills add yuchi-chang/no-cape --skill writing-meaningful-tests --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Writing Meaningful Tests?

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

Security grade badge for Writing Meaningful Tests
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/yuchi-chang-writing-meaningful-tests/badge)](https://www.skillsdirectory.com/skills/yuchi-chang-writing-meaningful-tests)

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: writing-meaningful-tests
description: Use when writing or modifying tests, adding mocks, or tempted to add test-only methods to production code
---

# Writing Meaningful Tests

A test is meaningful when it fails for exactly one reason: the behavior it names is broken. Tests that verify mocks, implementation details, or timing luck are coverage theater.

## Behavior, not implementation

- One behavior per test; the name states it ("retries failed operations 3 times", not "test1" or "retry works").
- Assert on outcomes a caller can observe, not on internal call sequences. A refactor that preserves behavior should not break the test.

## Mock discipline

- **Never assert on the mock.** `expect(mockFn).toHaveBeenCalledTimes(3)` verifies wiring, not behavior. If the assertion targets the mock, unmock it or assert on real output.
- **Understand side effects before mocking.** If the test depends on a side effect of the mocked method (a config write, a cache fill), mock one level lower — at the genuinely slow or external operation.
- **Mock the complete structure.** A partial mock response containing only the fields you remembered passes the test and fails the integration. Mirror the real schema.
- **No test-only methods on production classes.** Cleanup helpers belong in test utilities.
- Mock setup longer than the test logic → consider an integration test with real components instead.

## No sleeps — wait for conditions

Arbitrary delays (`sleep(500)`, `setTimeout(r, 50)`) are the top source of flaky tests: they pass on a fast machine and fail in CI under load.

```typescript
// ❌ guess at timing
await new Promise(r => setTimeout(r, 50));
expect(getResult()).toBeDefined();

// ✅ wait for the condition, with timeout and clear error
await waitFor(() => getResult() !== undefined, 'result ready', 5000);
```

A fixed delay is acceptable only when testing actual timing behavior (debounce, tick intervals): wait for the triggering condition first, derive the delay from known timing, and comment why.

## Trust check

A new test must be able to fail. Run it against broken or missing behavior at least once (comment out the fix, invert the condition). A test you've never seen fail proves nothing.

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…