Test data management (TDM) is the work of creating, protecting, delivering and refreshing the data your software is tested against. For a small team the rule that matters most is simple: generate test data from the start, and never let raw production records into a test environment. Everything below shows how to do that without building a platform.
I'm Hanad, a software engineer in Vienna. I build first versions and rebuilds of software products at a fixed price, and test data is one of the places where young products quietly go wrong. A prototype works on ten hand-typed rows, then meets real users and real data. Or someone copies the production database "just to debug," and now customer records sit in a staging environment with weaker protection.
Key Takeaways
- TDM covers six jobs: creating data, masking sensitive values, subsetting, delivering it to environments, connecting it to your tools, and versioning it.
- Copying production data into test environments is a documented risk. A US banking regulator's handbook recommends simulated synthetic data wherever possible.
- Masking, anonymization and synthetic data are different techniques. Pick by what the test needs, not by habit.
- A small team needs a short routine: define what each test needs, generate it, reset it, restrict access, delete it.
- Test data decisions are cheapest on day one of a build. Retrofitting them into a finished product costs far more.
Table of Contents
- What test data management actually includes
- Why it matters even for a two-person team
- The risk of copying production data
- Masking, anonymization and synthetic data: which one when
- A test data routine a small team can actually run
- Test data quality: how to know it is good enough
- Where test data goes wrong in prototypes
- Test data privacy: a short checklist
- Where I come in
- FAQ
- Sources
What test data management actually includes
IEEE Computer Society describes TDM as progressing through six stages: data creation (cloning production or generating synthetic data), obfuscation (masking and anonymization), subsetting (slicing data down to cut storage and infrastructure costs), delivering the data to the test environment at the right time and in a usable format, integrating with your existing tools, and versioning so tests are repeatable and changes are controlled.
That reads like an enterprise program, but each stage maps to a plain question a small team can answer:
| Stage | The question to answer |
|---|---|
| Creation | Where does the data come from: generated, or derived from real records? |
| Obfuscation | Which fields could identify a person, and how are they replaced? |
| Subsetting | What is the smallest dataset that still exercises this test? |
| Delivery | How does a developer or CI job get a fresh copy? |
| Integration | Does the data setup run inside the same pipeline as the tests? |
| Versioning | Can you recreate the exact dataset a failing test used last month? |
If you cannot answer one of these, that is where your next bug or compliance problem will come from.
Why it matters even for a two-person team
The same IEEE guide lists the payoffs: better traceability of which data your tests cover, lower costs from catching software-breaking bugs earlier, data provisioned by test type from one central place, better compliance and security through masking, reusable data, and more customer trust because bugs surface before launch. It also names the typical pains: slow manual environment setup, data that lacks fidelity, privacy risks, stale data, and tests corrupting each other's data when several people share one dataset. You can read the full list of challenges there.
Small teams feel these more sharply, not less. There is no QA department to notice that the shared staging database has drifted. One developer's experiment overwrites the records another developer's test depends on, and the failure looks like a code bug for an afternoon.
A second reason is delivery speed. If every test run needs hand-prepared data, you stop running tests often. Data that is generated and reset automatically is what lets a deployment pipeline run the same checks on every change.
The risk of copying production data
The shortcut is tempting: dump production, load it into staging, test against "real" data. Regulators describe why that is a problem.
The FFIEC IT Examination Handbook, written for US financial institutions but sensible for any team, lists six risks of non-production copies: privacy and misuse, security trade-offs, data corruption, vulnerabilities carried into production, secondary use, and data breach. Its recommendation is to use simulated synthetic data whenever possible. When production data is truly necessary, it calls for masking or sanitizing it, getting appropriate approval where masking is not feasible, and applying production-like identity, password, logging and monitoring controls.
European authorities say the same thing more bluntly. In 2021 the Norwegian Data Protection Authority fined a sports confederation after finding that testing with a large quantity of personal data was unnecessary and lacked adequate risk assessment, procedures, security measures and a legal basis. The authority noted that synthetic data or a much smaller dataset could have been used instead.
The EDPB's guidance on data protection by design and by default points the same direction. Default processing should include only the personal data necessary for each purpose, access should be limited, pseudonymization can be a safeguard, and data should be deleted or anonymized when no longer needed.
If you serve customers in the EU, or handle US health or payment data, a test database full of real people is a liability you carry every day it exists. If your product also sends data to language models, the same discipline applies to prompts: see how to keep raw PII out of prompts and the GDPR gaps to close for AI features.

Masking, anonymization and synthetic data: which one when
These three terms get used interchangeably. They are not the same.
- Masking takes a copy of real data and replaces sensitive values with realistic fictional ones, keeping the structure. A good mask is irreversible and keeps relationships between tables intact.
- Anonymization transforms data so people are no longer identifiable in a defined risk context, using techniques such as redaction, tokenization and aggregation. It is broader, and often less practical for testing because it can strip the detail tests need.
- Synthetic data is generated from scratch to match the structure, patterns and rules your workload needs. It is not derived from any real person's record, and it can be shaped to cover edge cases that rarely appear in production.
A simple way to choose:
| Your situation | Start with |
|---|---|
| New product, no real users yet | Synthetic data, from day one |
| Unit and integration tests | Synthetic, built by factories in code |
| Load and performance tests | Synthetic, generated at the volume you need |
| Debugging a bug that only appears in real data | A masked, limited subset, with approval and a deletion date |
| Demo environment for investors or customers | Synthetic, with a believable story |
Two details trip up masking in practice. First, it must be consistent: the same source value has to map to the same replacement everywhere, or joins across tables break and failures look like application bugs. Second, it must cover free text, notes and attachments, not only the obvious name and email columns. A support note that says "call Mrs. Keller on her new number" is personal data in a column nobody flagged.
Whatever you generate, check that it preserves uniqueness, valid formats and the distributions that matter. A dataset where every order is for one item will never reveal the bug in your multi-item discount logic.
A test data routine a small team can actually run
You do not need a platform to manage test data well. You need a routine that is short enough to survive deadlines. This is the one I use as a baseline when I build products.
1. Write down what each test needs
Start from the purpose of the test, then list the data properties it requires: a customer with an expired card, an invoice in a foreign currency, a user with two roles, an account with 10,000 records. Name the property, not the row. This is what makes data reusable.
2. Generate it in code
Build small factory functions that create users, orders and subscriptions with sensible defaults and let a test override only what it cares about. Keep them in the repository so the data setup is reviewed like any other code, and so a new developer can read it on day one. Plain, widely known tooling matters here: the next developer should be able to pick it up without learning a custom framework.
3. Use a limited production subset only when you must
Sometimes a bug truly lives only in real data. Then follow the FFIEC sequence: mask first, get approval, restrict access, and set a deletion date. Mask at the source, before data leaves the production boundary, never after it lands in staging.
4. Isolate and reset every run
Each test run should start from a known state and end by restoring it. Shared, mutable test data is the cause of most "it passes on my machine" arguments. Per-run isolation also fixes the data-corruption problem IEEE lists among the common TDM challenges.
5. Restrict access and keep a record
Give people the access they need, for the time they need it, and log how datasets were provisioned. Test environments should get security testing too, because attackers do not care that a server is labeled "staging."
6. Delete on schedule
Retention is part of the job. That includes exports, logs, reports, screenshots and backups, which often outlive the database they came from. Define when each expires and enforce it.
7. Validate before you trust
After generating or masking, run a quick check: row counts, foreign keys resolve, formats are valid, no real emails or phone numbers remain. A few seconds of checking saves hours of chasing failures that were really data problems.
Test data quality: how to know it is good enough
Good test data is relevant to the scenario, available to the people who need it, kept current as the software changes, and compliant with the privacy rules that apply to you. Those four checks, taken from common TDM practice, fit on a sticky note.
Relevance deserves the most attention. Realistic is not the same as useful. The best datasets include the awkward cases: a name with an apostrophe, a refund on a canceled subscription, a timezone boundary, an empty state. Generated data is well suited to this because you can add a case the moment a bug reveals it, and it stays in the suite forever.
Format validity matters most where money moves. If your product handles payouts or supplier payments, test data should include account identifiers that pass format checks and ones that fail them, so your validation paths are exercised. For a view of what bad payee data does downstream, see this article on data quality checks for payments.
Where test data goes wrong in prototypes
Most of the founders I work with arrive with a product built quickly in a no-code or AI builder. Those tools are good at producing something that runs. They are not good at separating test data from live data. Typical findings:
- One database serves both the demo and real users, so "test" accounts appear in real reports.
- Seed data was copied from a customer's spreadsheet and never cleaned.
- There are no automated tests, so there is no test data at all, only whatever someone clicked in manually.
- Staging does not exist, so changes are tried on live data.
None of this is a moral failing. It is what speed looks like. But it surfaces fast in a security questionnaire or investor review. If that is coming, the software due diligence checklist shows what a reviewer will look for, and the AI audit checklist covers the AI-specific side. The broader habits are collected in this list of engineering best practices for software teams.
Test data privacy: a short checklist
When the question is purely about keeping people's data safe in non-production systems, these points carry most of the weight:
- Default to synthetic data. Treat any real record in a test system as an exception that needs a reason.
- If you must use real data, mask it at the source and keep relationships consistent.
- Include free text, files and backups in the scope, not just database columns.
- Apply the same access controls and monitoring as production.
- Log who received which dataset and when.
- Set a retention period and delete on time.
- Where data protection law applies, keep the necessity and purpose of any personal data in testing documented. If you process EU personal data, the data residency questions for your vendors belong on the same list.
This is engineering guidance, not legal advice. If your product handles health, financial or children's data, ask your privacy counsel or data protection officer to confirm which rules apply to your test environments.
Where I come in
If you have a product that needs a proper foundation, this is the kind of detail I build in from the first commit, so test data, staging and deployment are not an afterthought. I take on fixed-price work in three forms: rescuing and rebuilding a prototype, building a first real version, or turning one manual workflow into a working tool. A Prototype Audit is €1,500, takes 3 to 5 days and is credited against the build. Builds start from €12,000 for your app, and you own the code from the first commit.
My view: build the data discipline in on day one
I have worked on systems for Deutsche Bahn, BMW and the Bundesrechenzentrum, and the pattern is the same at every scale. Teams that decide early how test data is created, isolated and deleted spend their time on features. Teams that decide late spend it on cleanups, awkward conversations with security reviewers, and tests nobody trusts.
That is why I work with a deliberately plain stack: TypeScript, Next.js, Node, SQL. Factories that generate data in code, a staging environment that never touches real customers, and a pipeline that resets state on every run are easy to build when the product is new. They are also easy for the next developer to read, which is the point of owning your code.
I do the work myself, end to end, in two to four weeks at a fixed price, so the person you talk to is the person who writes the code. Decisions like "what data does this test need" get made once, by someone who understands the whole product, and written down where you can see them.
Hanad Kubat
FAQ
What is test data management in simple terms?
It is the process of providing, preparing, securing and maintaining the data used to test software. That includes deciding what data tests need, generating or masking it, delivering it to test environments, and refreshing and deleting it afterward.
Can I use production data for testing?
It is risky, and regulators advise against it as a default. The FFIEC handbook recommends simulated synthetic data whenever possible, and masking or sanitizing production data plus approval and production-grade controls when it is unavoidable. European authorities have also fined organizations for testing with unnecessary personal data.
What is the difference between data masking and synthetic data?
Masking starts from real records and replaces sensitive values, keeping the structure. Synthetic data is generated from scratch and is not derived from any real person. Synthetic data suits new products and edge cases, while masked subsets are for the rare bug that only appears in real data.
How should a small team start with test data management?
Write down what each test needs, generate that data in code, and reset it on every run. Then restrict access, log who gets what, and set a deletion date. That covers most of the value without any special platform.
Sources
- A Guide To Test Data Management, IEEE Computer Society
- FFIEC IT Examination Handbook: Non-Production Environments
- Guidelines 4/2019 on Article 25 Data Protection by Design and by Default, EDPB
