# Mock Data Worth Testing Against — Routebase

> Static, generated and fixture data as three sources with three different failure modes, why a field filled with the word string ruins every layout, and how locale and time format quietly break a client.

Canonical page: https://routebase.dev/guides/api-mocking/mock-data-generation/
Chapter 3 of 10 · API Mocking · Last reviewed 2026-09-13 · The Routebase Team

A mock that returns the right shape with the wrong values is still useful, and it is much less useful than people assume. Almost every layout bug, sorting bug and formatting bug that surfaces on integration day was invisible against the mock because the data was too tidy.

## Three sources, three different problems

Response bodies come from one of three places, and mixing them is normal once you know what each one is for.

| Source | Strength | What it hides |
|---|---|---|
| Static | Exact, readable, stable across runs | Every request returns the same tidy case |
| Generated | Variety, plausible values, unlimited volume | Nothing can assert on a value that changes |
| Fixture | One record set shared by mocks, tests and docs | Only as good as the records somebody curated |

Static is where most mocks start and where most of them stay. Generated is what makes a list view honest, because twenty different names reveal a column that only fits fifteen characters. Fixtures are what let a test assert on a value at all, since an assertion against a generated name is an assertion that fails eventually.

The mixed case is the one worth reaching for. Real reference records supply the ids, names and prices your tests depend on, and generated values fill everything nobody asserts on, so the response is stable where it matters and varied everywhere else.

## The placeholder problem

A schema-driven generator that reads only types fills every string field with the same value, and that value is usually the word `string`.

The response validates. It is also a uniform grid of five-character cells. Nothing there reveals that the product name column truncates, that the sort is lexical rather than numeric, or that a currency field renders without a separator. The frontend built against it looks finished and has never met a real value.

Reading the field name fixes most of that. A field called `email` produces something with an at sign in it, `price` produces a decimal, `createdAt` produces a timestamp, and the result is a response somebody can judge. That mapping is a lookup from name patterns to generators, which means it is configurable and worth configuring for the field names your domain actually uses.

## The cases that only appear on purpose

Plausible values are the floor rather than the ceiling, because the states that break clients are the ones at the edges.

**The empty list.** Every collection endpoint returns one eventually, and the zero state is the screen nobody built. A mock that always returns rows guarantees it stays unbuilt.

**The long value.** Names, addresses and titles have a real distribution and it has a long tail. One deliberately long record in your fixture set finds more layout bugs than a hundred generated short ones.

**The missing optional field.** A field marked optional in the schema will be absent in production, and a mock that always includes it teaches the client to assume it is there.

**The large page.** A list of three behaves nothing like a list of five hundred, either for the layout or for the rendering cost.

## Locale and time are a quiet failure

Two generator settings cause more integration surprises than their size suggests, because they are set once and then forgotten.

Generated names, cities and addresses follow a locale. A frontend developed against English test data and deployed to a German market meets longer words, different address shapes and a different sorting order on the same day as everything else.

Timestamps are worse, because the format is invisible in a rendered screen. A client built against ISO 8601 strings and pointed at an API returning Unix timestamps fails on every date field at once. The mock that could have caught it was configured with the other format. The same applies to the timezone, where a date rendered in local time is off by a day for part of the world exactly often enough to be dismissed as flaky.

None of that is exotic. It is a handful of settings that decide whether the mock produces the shapes your client will actually meet.

## In Routebase

A rule's body is produced in one of four modes, and the choice is per rule rather than per server.

_Screenshot: Locale, time format and timezone are set once for the organisation and inherited by every new mock server, and the matching table underneath is what turns a field name into a generator rather than a placeholder._

**Static Body** returns exactly what you typed, with JSON validation and a format button. **Dynamic** treats the body as a template where `{{faker.*}}`, `{{request.*}}` and `{{state.*}}` placeholders resolve on every request, so `{{request.path.id}}` echoes the id that was asked for. **Fixture Reference** serves a project test-data fixture directly, and **Smart Mock** uses fixture values first and fills the rest with generated ones.

Fixtures can be transformed on the way out with a pipe chain, so `where:role=admin | first | toJson` serves one record rather than the whole set, and the same fixture backs your test assertions. The faker catalogue covers people, contact details, identifiers, dates, numbers, addresses, business fields, web values, colours, text, finance and media, and the generated values follow the locale, time format and timezone configured for the server.

Which generator a field gets is decided by matching rules. The built-in patterns ship grouped by category and can be toggled individually. Your own rules match exactly, by wildcard or by regular expression, with a live preview showing the value a pattern would produce. Custom rules apply at generation time, so a banner offers to regenerate the affected rules once you change them. The [Mock Server](https://docs.routebase.dev/mock-server/) guide covers body modes and matching rules, [Mock Server Settings](https://docs.routebase.dev/mock-server-settings/) covers locale and time, and [Test Data](https://docs.routebase.dev/test-data/) covers the fixtures both halves share.

## Frequently asked questions

### How do you generate realistic mock data?

Map each field to a generator by its name as well as its type, so a field called email produces an address and a field called city produces a city. Type alone is not enough, because every string in the schema then comes back as the same placeholder and the result tells you nothing about how the real values will look. Names carry the meaning, and a generator that reads them turns a valid response into a plausible one.

### Should mock data be random or fixed?

It depends on who is reading the response. A person building a screen wants variety, because identical rows hide the layout problems that real data will cause. An automated test wants the same value every run, since an assertion against a random name is an assertion that fails on a schedule. The usual answer is generated data for development and fixed reference data wherever something asserts on a value.

### Can mock data and test data come from the same place?

They should, and the argument is drift rather than convenience. When the mock serves one set of records and the tests assert on another, the two copies diverge and nothing reports it. Pointing both at the same fixture means a change to that data changes what the mock returns and what the tests expect in the same commit.

### Why do mock responses look fine and still break the client?

Because valid and realistic are different properties. A response full of three-character strings, single-item lists and identical timestamps satisfies every schema and exercises none of the cases a layout has to survive. The states that break a client are the long name, the empty list, the missing optional field and the date in another timezone, and none of those appear unless the mock produces them on purpose.

---

[Routebase](https://routebase.dev/) — [Sign up](https://app.routebase.dev/): Every account starts with a 14-day Pro trial — no credit card required.
