Test Data Management

Expected level: Working

Test data is the input and the starting state a test relies on: records in a database, files, configuration and user accounts. Managing it means making sure every test begins from a known state, and that you can recreate that state at will.

What good test data looks like

Test data should be predictable (the same data every run), isolated (tests do not affect each other), minimal (only what the test needs) and realistic enough to expose real problems.

Where test data comes from

  • Created in the test itself: each test builds the objects or rows it needs. This is the most readable approach, and the best default.
  • Builders and factories: helper code creates a valid object with sensible defaults, and the test overrides only the fields that matter, such as aCustomer().withCountry("NO"). A shared helper that creates standard sample objects is known as an object mother.
  • Fixtures and seed scripts load a fixed data set before a test run. They suit reference data such as countries or roles, but large shared fixtures become hard to understand.
  • Copies or exports of production data are convenient but risky. See below.

Keeping tests independent

  • Create data at the start of the test and remove it at the end, or run each test in a database transaction that is rolled back.
  • Or start from a fresh throwaway database for each run, for example in a container.
  • Do not let one test depend on data left behind by another.

Watch for hidden inputs: the current time, random values, time zones and locale. Pass them in, or fix them in the test. See Dates, Times and Time Zones.

Edge cases and volume

Think beyond one tidy record: empty strings, very long text, accented and non-Latin characters, apostrophes, boundary dates, zero and negative numbers. Performance and paging problems only show with larger volumes, so generate bulk data with a script when you need it.

Production data and privacy

Never copy real personal data into development or test systems without a clear reason and approval. Prefer synthetic data, or data that has been anonymised or masked. Also keep real credentials out of fixtures and scripts. See Data Privacy Awareness and Secrets Management.

Keep seed scripts and builders in the repository next to the tests, and make a reset one command. See Integration Testing for where this matters most, and Environments for what data each environment holds.

Try it

Write a small builder or factory function for one of your domain objects, with valid defaults. Use it in two tests that each override a different field. Then run both tests in reverse order and in parallel if your framework allows it, and fix any dependency between them.

Common mistakes

  • Letting one test depend on data left behind by another.
  • Copying real personal data into test systems.
  • Using large shared fixtures that nobody understands.
  • Leaving hidden inputs such as the current time or random values uncontrolled.

Check yourself

  • What makes a test data set predictable and isolated?
  • What is an object mother?
  • How would you handle the current time in a test?

Related topics

Terms

Further reading