agentsclimarketplace

Test data builder

Skill SkillMedev/qa-test-automation/skills/test-data-builder

Build a test suite that actually catches bugs — and stops flaking.

Install
npx -y skills add SkillMedev/qa-test-automation --skill test-data-builder

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Builds realistic domain fixtures, factories, and edge-case datasets with the builder pattern and valid defaults, so each test owns exactly the data it asserts on. Use when someone asks "how should I set up test data", "my fixtures broke half the suite", "make a factory for this model", "why is this test flaky only in CI", or a test needs domain objects, seed data, or boundary inputs. Do NOT use when a test needs to fake a network call, database client, clock, or third-party SDK - use mock-stub-designer instead; do NOT use for designing the assertions or test cases themselves - use tdd-expert instead.

SKILL.md

6.3 KB, as published. Nobody here has run it

Test Data Builder

Produce per-test domain data that is realistic, deterministic, and isolated. The costly failure this prevents is the shared fixture file that becomes an append-only god object: one test tweaks a record, three unrelated tests start flaking, and nobody can delete a fixture row because nobody knows who depends on it. Builders with valid defaults make every test self-describing and every failure reproducible.

Operating procedure

Order matters: defaults must be valid before overrides mean anything, and determinism must be in place before you add realistic randomness.

Step 1: Gather inputs

Collect before writing a factory. Defaults in parentheses; label guesses as guesses.

  1. The domain object(s) under test and their required fields.
  2. The stack's factory library (FactoryBot for Ruby, Fishery or test-data-bot for TypeScript, factory_boy for Python, Bogus/AutoFixture for .NET; default: hand-rolled builder if none exists).
  3. Whether tests touch a real database, and the isolation mechanism available (per-test transaction rollback preferred).
  4. The invariants a "valid" object must satisfy - validations, foreign keys, non-null constraints.

Step 2: Build per test, never share a global fixture

Construct the objects each test needs inside that test via a factory or builder (FactoryBot, Fishery, test-data-bot, Mother objects). Do not load one static fixture file for the suite - shared mutable fixtures silently couple tests, and the coupling only surfaces as ordering-dependent flakes.

Step 3: Expose a builder with valid defaults; override only what the test cares about

Write aUser().withRole('admin').build() so the override is the test's documentation and the reader ignores the irrelevant fields. Defaults must always produce a valid, persistable object: when a new required field is added to the schema, set it once in the factory and zero unrelated tests break.

Bad - the reader cannot tell which of nine fields the test is actually about, and the next required field breaks this test and forty like it:

const user = new User({
  id: 42, name: 'Test User', email: '[email protected]',
  role: 'admin', locale: 'en', createdAt: new Date(),
  emailVerified: true, plan: 'free', avatarUrl: null,
})
expect(canDeleteWorkspace(user)).toBe(true)

Good - one override, and it is the point of the test:

// user-builder.ts - valid defaults live in exactly one place
export const aUser = () => {
  let attrs: UserAttrs = {
    id: seq(), name: faker.person.fullName(),
    email: faker.internet.email(), role: 'member',
    locale: 'en', createdAt: fixedNow, emailVerified: true,
    plan: 'free', avatarUrl: null,
  }
  return {
    withRole: (role: Role) => { attrs = { ...attrs, role }; return api },
    unverified: () => { attrs = { ...attrs, emailVerified: false }; return api },
    build: () => new User(attrs),
  }
  // (api = the object above; shown flat for brevity)
}

// the test
const admin = aUser().withRole('admin').build()
expect(canDeleteWorkspace(admin)).toBe(true)

Step 4: Make data realistic but deterministic

Use Faker (Faker, faker.js, Bogus) for names, emails, and addresses so fixtures resemble production and surface encoding and length bugs that "test" never would. Seed the faker with a fixed seed in CI so a failing run reproduces exactly. The rule: randomness may vary the shape of inputs; it must never decide whether an assertion passes.

Step 5: Build the inputs that break code

Deliberately construct: empty strings, unicode and emoji, very long strings, leading/trailing whitespace, nulls, zero, negative numbers, max integers, timezone-boundary dates, and duplicate keys. For ranges, always build the boundary value and the just-over-boundary value - off-by-one bugs live exactly there. Name each edge-case test after the boundary it exercises. For input spaces too large to enumerate, reach for property-based generators (Hypothesis, fast-check) instead of hand-picking.

Step 6: Keep persistence cheap and isolated

Build in memory by default; only persist (create vs build) when the test needs a real row. Wrap DB-touching tests in a transaction rolled back per test so factories never leak state between tests. Do not rely on sequences or global counters surviving across tests - the suite must pass in any order and in parallel.

Deliverable

Produce, for each domain object under test: a builder or factory whose bare defaults yield a valid persistable object, override methods named for intent (unverified(), withRole()), a seeded-faker configuration for CI, and an edge-case dataset covering the boundaries in Step 5 with each case named for its boundary.

Do NOT

  • Do not build elaborate object graphs a test never asserts on - every extra field is a false signal about what the test checks.
  • Do not wrap a one-field value object in a builder; a literal is clearer than ceremony.
  • Do not let a builder reach across the boundary to fake network, DB clients, clocks, or third-party SDKs - that is mock-stub-designer's job, and mixing the two makes builders untestable.
  • Do not seed randomness from the wall clock or leave it unseeded in CI - an unreproducible flake costs more than the realism buys.
  • Do not "fix" a broken shared fixture by adding another record to it; migrate the affected tests to builders instead.

Quality bar

  • Every factory's defaults alone produce a valid, persistable object.
  • A reader can tell what a test asserts from its overrides without opening the factory file.
  • The suite passes identically on repeated runs and in any order; no test depends on another's data.
  • Edge-case tests name the specific boundary they exercise.
  • Adding a required field to the schema touches exactly one factory, zero tests.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.