Skip to content
ZeroServer.tools
All guides

Generating Fake Test Data for Development and QA

June 5, 2026 · 4 min read

Testing with real user data is a privacy risk and often a compliance violation. Testing with no data means your tests don't reflect reality. Fake data threads the needle: realistic-looking records that let you test properly without exposing anyone's information.

This guide covers strategies for generating fake test data — from quick one-liners to seeded generators for reproducible test suites.

Why fake data matters

Real data causes real problems in test environments:

  • Privacy regulations (GDPR, CCPA, HIPAA) restrict where real personal data can be stored and who can access it. Dev laptops and staging servers often don't qualify.
  • Security surface — a breach of your test database that contains real emails and passwords is still a breach.
  • Test isolation — real data changes. A test that passes today may fail tomorrow because a real user's email format changed.

Fake data is deterministic (when seeded), portable, and risk-free.

What "realistic" means for test data

Realistic fake data is structurally valid:

  • Email addresses have the right format ([email protected])
  • Phone numbers match the expected pattern for the target locale
  • Addresses reference real city names, not "city123"
  • Names don't include characters that break your name-parsing logic

It doesn't need to correspond to real people — it just needs to not break your validation.

Browser-based fake data generation

The Fake Data Generator produces records in JSON or CSV format, with fields you select:

  • id, name, email, phone
  • age, job, company
  • address, city, state, zip
  • username

All data is generated deterministically using a seeded PRNG (no Math.random() — seed-based Math.sin(seed)), so the same settings always produce the same records. This is important for reproducible tests.

Seeded generation for reproducible tests

Randomness in tests is dangerous — a test that passes with one random dataset and fails with another is flaky. Use a seed:

// Simple seeded PRNG (good enough for fake data, not for crypto)
function seededRand(seed, max) {
  return Math.abs(Math.sin(seed) * max | 0) % max;
}

const NAMES = ["Alice", "Bob", "Carol", "David", "Emma"];
function fakeName(recordIndex) {
  return NAMES[seededRand(recordIndex * 137, NAMES.length)];
}

// Same index always produces same name
fakeName(0); // → "Alice" every time
fakeName(1); // → "Emma" every time

This approach requires no external library and works in any JavaScript environment.

Generating valid emails

The simplest approach: ${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com. The example.com domain is IANA-reserved for documentation and testing — it will never resolve to a real service, so test emails sent there are inherently safe.

function fakeEmail(first, last, index) {
  const domains = ["example.com", "test.local", "qa.internal"];
  const domain = domains[index % domains.length];
  return `${first.toLowerCase()}.${last.toLowerCase()}${index}@${domain}`;
}

Generating valid phone numbers

US format: +1-NXX-NXX-XXXX where N is 2–9 (first digit of area code and exchange can't be 0 or 1):

function fakePhone(seed) {
  const area = seededRand(seed, 800) + 200;       // 200–999
  const exchange = seededRand(seed + 1, 800) + 200;
  const subscriber = seededRand(seed + 2, 9000) + 1000;
  return `+1-${area}-${exchange}-${subscriber}`;
}

Generating addresses

Combine arrays:

const STREETS = ["Main St", "Oak Ave", "Maple Dr", "Cedar Ln"];
const CITIES  = ["Portland", "Austin", "Denver", "Chicago"];

function fakeAddress(seed) {
  const num  = seededRand(seed, 9000) + 100;
  const st   = STREETS[seededRand(seed + 1, STREETS.length)];
  const city = CITIES[seededRand(seed + 2, CITIES.length)];
  return `${num} ${st}, ${city}`;
}

Generating IDs

For UUIDs in tests, use the UUID Generator or the Web Crypto API:

function fakeUuid() {
  return crypto.randomUUID(); // supported in all modern browsers
}

For sequential IDs: i + 1. For ULIDs: ULID Generator.

Generating passwords for test accounts

Never use real passwords in test data. Generate random strings and hash them immediately:

import bcrypt from 'bcryptjs';

async function fakeHashedPassword(seed) {
  // Deterministic "random" password
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  const password = Array.from({ length: 16 }, (_, i) =>
    chars[seededRand(seed + i, chars.length)]
  ).join('');
  return bcrypt.hash(password, 10);
}

Use the Bcrypt Generator to pre-compute hashes for fixed test accounts.

Output formats

JSON (for API testing and seeding)

[
  { "id": 1, "name": "Alice Smith", "email": "[email protected]" },
  { "id": 2, "name": "Bob Johnson", "email": "[email protected]" }
]

Import directly into API integration tests or seed scripts.

CSV (for spreadsheet imports and database bulk load)

id,name,email,phone
1,Alice Smith,[email protected],+1-203-456-1001
2,Bob Johnson,[email protected],+1-415-789-2002

Load with COPY (PostgreSQL), LOAD DATA (MySQL), or a spreadsheet import.

Privacy-safe sharing

When you need to share a dataset for a bug report or demo:

  1. Replace real names/emails with fake ones from the generator
  2. Keep all other field values (amounts, dates, status flags) — these are usually the interesting part
  3. Use the same seed so you can regenerate the same "sanitized" dataset

The Fake Data Generator generates output client-side — no data is uploaded or logged.

When to use the browser tool vs. a library

Situation Use
Quick demo or one-off seed Browser Fake Data Generator
Automated test suite Seeded code function (reproducible)
Large datasets (10k+ rows) faker.js, @faker-js/faker, or similar
Locale-specific data (e.g. Japanese names) @faker-js/faker with locale setting

For format conversion on the output, use JSON Formatter or CSV to JSON.