You have tests now, but a test needs something to run on. Some of your code also reaches out to the real world: a payment provider, an email sender, another API. A test must never charge a real card, send a real email, or depend on data that changes underneath it. This chapter gets you controlled test data and safe stand-ins for those outside services.
8.3.1Tests need their own data
A test can only check "did I get the right answer" if it knows the answer in advance. That means predictable, controlled input, never your real or production data, which changes the moment a user edits something.
Prepared test data like this is a fixture: a fixed, known record your test runs against. Your agent writes these; here is the shape:
The test uses testUser and knows exactly what to expect, every run, forever.
8.3.2Make data with a factory, not by hand
Writing each fixture by hand gets tedious fast, and one change to the shape of your data breaks every one you typed out. When you need many records, or just realistic-looking ones, use a factory: a small function that builds fake data on demand.
A library like Faker fills in believable names, emails, and dates for you:
Call makeUser() for a random one, or makeUser({ plan: "pro" }) to pin the one field a test cares about.
8.3.3Never call the real service in a test
Your code calls out to services you do not own: a card gets charged, an email gets sent, another API answers. In a test, none of that can happen. You cannot spend real money or send a real email a thousand times a day.
So you swap the real service for a mock: a stand-in that returns a canned response instead of doing the real thing. Tests stay fast, and they never touch the outside world.
For code that talks to an API over HTTP, Mock Service Worker intercepts the request and hands back whatever you tell it:
The code under test thinks it charged a card. Nothing left your machine.
8.3.4Reset between tests, so they don't leak
A test that leaves data behind poisons the next one. Say test A creates a user and test B counts users. B passes only because A ran first. The day you run B alone, it fails for no reason you can see.
So every test starts from a clean slate. Reset the test database and any shared state before each one runs, so no test can depend on the leftovers of another. Your agent wires this into the test setup once.
You have one database, so where does the test one come from? Three options: a second database on the server you already run, a throwaway SQLite file for speed, or a fresh container per run. Use the same engine as production for anything testing SQL you actually rely on, and the fast throwaway one for everything else.
Then treat the connection string as a hard rule, because "reset before each test" means "delete everything". It points at the test database and nowhere else. Point it at your development or production database and the next test run wipes it.
Rule of thumb: any test must pass on its own, in any order. If it only passes after another test runs, something is leaking, reset it.
This prompt sets up test data and safe fakes for your stack:
Do this now: paste the prompt and name the outside service your app calls first. Let your agent replace it with a mock before another test ever risks the real thing.