# Tests as the safety rail

Web page: https://academy.memberpress.ai/courses/code-intro/l6/

Lesson 6 of 8 in [Claude Code — Getting Started](https://academy.memberpress.ai/courses/code-intro/), 8 min.

Video: https://www.youtube.com/watch?v=oiVu2bMkO5Y

The thing that makes Claude Code dangerous on a codebase without tests is not that Claude writes bad code. It is that you have no way to know whether the code is bad until something breaks in production. Tests give you that knowledge immediately. They do not make Claude better — they make Claude's errors visible before they ship.

**Why tests change the risk profile**

When Claude edits tested code, the test suite runs after the edit and either passes or fails. A failure tells you which specific expectation was violated and which line violated it. You do not have to read the entire diff to find the problem — the test points at it.

Without tests, the diff is the only check. The diff shows you what changed. It does not show you what the change breaks downstream. Those downstream breakages are invisible until runtime.

**Establishing a baseline before Claude starts**

Before you give Claude a task, run the test suite and confirm it passes. This is not optional. If tests are already failing, you cannot attribute a new failure to Claude's changes.

```bash
npm test
# → Test Suites: 12 passed, 12 total
# → Tests:       87 passed, 87 total
```

After Claude finishes, run the test suite again. Any new failures are Claude's responsibility. Any failures that were present before Claude started are your responsibility.

```bash
# [Claude makes changes]
npm test
# → Test Suites: 11 passed, 1 failed, 12 total
# → FAIL src/api/user.test.ts
# →   ● UserController › should return 404 when user not found
```

That failure is the information. Read it, then tell Claude what it says:

```
> The test UserController › should return 404 when user not found is failing.
> The error is: Expected status 404, received 200. Fix only that case.
```

**Writing tests before Claude touches an untested function**

If the function you want Claude to refactor has no tests, write the tests first. You can use Claude to write them — but read every test before you run it. A test that always passes is not a test; it is documentation that happens to be executable.

Minimal test coverage for a function: one test for the happy path, one test for the primary error case. For a function that handles user data, add one test for an empty or malformed input.

```bash
npm test src/api/user.test.ts
# → Tests: 3 passed, 3 total
```

Now give Claude the refactor task. The tests will tell you if the refactor breaks the contract.

**What "load-bearing" means**

Payment processing, authentication, data migrations, anything that writes to a database, anything that sends an email or an external notification — these are load-bearing. They get tests before Claude touches them. Static copy, CSS, internal tooling scripts — lower risk, more tolerance for a lighter bar.

**If you get stuck**

- Claude wrote a test that always passes: a test that mocks its own subject, that never asserts anything, or that catches errors silently will pass even when the code is broken. Read the assertion lines. An assertion must fail under some input.
- The test suite takes too long to run to use as a feedback loop: run only the tests for the file Claude is editing. `npm test -- --testPathPattern=user.test.ts` or the equivalent in your framework.
- Claude's change passes all tests but feels wrong: trust the feeling. Tests cover specified behavior, not all behavior. Add a test for the case that worries you, run it, confirm it passes or fails.

**Cross-reference**

l4 ("Asking for a refactor") covers how to write the brief that Claude will execute against your tests. The brief's success criterion should reference the test suite: "All existing tests pass" is the minimum bar.

**Deliverable**

Identify one function in your codebase that is load-bearing and has no tests. Write three tests for it — happy path, error case, edge case. Confirm all three pass before you run Claude on that function.

## Try these prompts

- Write the minimal test coverage for a function that validates a user's email and password on login — happy path, primary error case, and one edge case.
- Write the Claude Code message to send when a test failure says: Expected status 404, received 200. Name the exact location to fix.
- Explain in two sentences why a test that mocks its own subject — one that catches errors silently — will always pass even when the code is broken.

Next: [Ship a small PR end-to-end](https://academy.memberpress.ai/courses/code-intro/l7/)
