DeepSeek can help you think of software test cases that a tidy example dataset misses: a price one cent below a threshold, a Boolean where an integer belongs, or two valid options whose combination changes the outcome. The useful result is a small collection of deliberate fixtures with clear expected behavior. A thousand plausible-looking records are much less valuable if nobody can explain which rule they exercise or whether their expected answers are correct.

This guide shows how to turn model-assisted ideas into dependable synthetic test data. The running example is a fictional parcel-quote function with a free-shipping threshold. You will define its contract, design meaningful coverage, ask DeepSeek for candidate inputs, and admit cases through a local validation process. The complete Python example and fixture file use only the standard library and run without a network connection.

All examples, expected outcomes, prompts, and illustrations in this article were authored for the tutorial. The local test results demonstrate the supplied code and data; they do not measure DeepSeek’s performance, and no live model calls were made. The process is designed so you can review a useful manual experiment before deciding whether an approved API integration would save your team time.

1. Choose the kind of synthetic data you actually need

“Synthetic data” can mean several different things. A unit-test fixture is a carefully chosen input paired with a known result. A demonstration dataset makes screens understandable. A load-test dataset creates enough volume and relationships to exercise infrastructure. A statistically representative dataset tries to preserve selected properties of a population. These purposes require different evidence. A model-generated list that looks believable does not automatically satisfy all four.

For a unit test, unusual records are often the most useful. You may intentionally include an impossible quantity, a missing field, or an unsupported delivery option. For a product demonstration, those records could distract from the experience you want to show. For a load test, you might need millions of deterministic rows, making a local generator more suitable than asking a language model to produce every record. Decide the intended use before deciding how much data to generate.

This article focuses on contract-driven software fixtures. The objective is to expose incorrect behavior in a small function and make failures easy to reproduce. It does not build an anonymized copy of a production database or establish statistical similarity to real customers. That narrower goal lets us work entirely from invented values and explicit rules, without transferring customer examples to a hosted model.

A useful division of work is to let DeepSeek suggest missing situations and readable descriptions, then let reviewed requirements determine expected results. A developer can write the basic threshold cases directly. The model’s additional value may be suggesting a type confusion, an interaction between delivery options, or a contradictory requirement. Evaluate those contributions by whether they add a genuinely new check, rather than by how many lines of JSON they produce.

2. Write the contract before generating records

Our fictional application quotes a delivery fee from four input fields: subtotal_cents, item_count, region, and service. It does not calculate taxes, convert currencies, contact a carrier, or arrange delivery. Monetary values are integer cents in a single fictional accounting unit. This deliberately limited example makes it possible to check every expected result by hand and keeps unrelated commercial assumptions out of the test design.

The subtotal must be an actual integer between zero and one million, inclusive. The item count must be an actual integer from one through fifty. Boolean values are invalid even though Python treats bool as a subclass of int. A decimal JSON token such as 5000.0 is also invalid under this particular contract. Another application might choose to normalize equivalent numeric values, but that would be a different documented rule and should have different tests.

The region is either mainland or remote, and the service is either standard or express. Standard delivery costs 500 cents; express costs 1,200 cents. Remote delivery adds 700 cents to either base fee. Free delivery applies only when the region is mainland, the service is standard, and the subtotal is at least 5,000 cents. The threshold does not remove the remote surcharge or make express delivery free.

Validation order is part of the contract. An input must contain exactly the four required keys. A missing or extra key produces a rejection identifying “keys,” without continuing into value checks. When the keys are correct, the function reports every invalid field name in sorted order. Success returns an object with status “ok” and fee_cents; rejection returns status “reject” and a fields list. No automatic correction or string-to-number conversion occurs.

These details prevent several plausible disagreements. A subtotal of zero is valid because the contract permits it. An item count of zero is invalid. A subtotal of 5,000 qualifies at the threshold rather than only above it. An extra coupon field is rejected instead of being silently ignored. If your actual product needs a different rule, change the contract deliberately before copying the example. A model should not settle those decisions by guessing which behavior feels conventional.

Keep the source of each rule close to the fixture specification. In a real project, that might be a reviewed API contract or a product decision with an owner and date. A screenshot can reveal current behavior but may not establish intended behavior. When existing tests, documentation, and product expectations conflict, record the conflict and resolve it with the responsible maintainer. Generating more records cannot compensate for an unresolved requirement.

3. Design coverage around boundaries and combinations

Start with a coverage checklist rather than a request for “diverse examples.” For the free-delivery threshold, use 4,999, 5,000, and 5,001 cents with mainland standard delivery. These three neighboring values distinguish an inclusive threshold from an exclusive one and verify that the fee changes at the intended location. Repeating a normal 8,000-cent order with twenty different labels does not provide the same evidence.

Next, hold the subtotal at 5,000 while changing region and service. The four meaningful combinations produce fees of zero, 1,200, 1,200, and 1,900 cents. Two combinations happen to produce the same fee for different reasons: remote standard combines a 500-cent base with a 700-cent surcharge, while mainland express uses its 1,200-cent base. Keep both cases because a future refactor could break either path independently.

At a subtotal of 5,000 cents and one item, mainland standard shipping costs 0 cents, remote standard costs 1,200 cents, mainland express costs 1,200 cents, and remote express costs 1,900 cents.
At the same 5,000-cent subtotal, region and shipping method change the result. Only mainland standard is free; all amounts are in cents.

Cover the valid endpoints separately from the fee threshold. Zero and one million are valid subtotal values; negative one and one million plus one are outside the permitted range. Item counts one and fifty are valid, while zero and fifty-one are invalid. The tutorial combines some valid endpoint checks into one record to keep the example compact. In a larger suite, separate cases can make failures easier to diagnose when individual bounds change.

Type cases deserve their own category. JSON true, the string “5000,” the number 5000.0, and the integer 5000 may look interchangeable after casual coercion. Under our contract they are not. Deliberately choose which representations your boundary accepts. Otherwise, a generated dataset full of well-formed integer tokens can leave a surprising acceptance path completely untested. An invalid record is valuable when its rejection is the behavior you intend to verify.

Then look for error interactions. If a request lacks item_count and also has a negative subtotal, should it report one error or both? Our contract returns only the keys error because shape validation has precedence. If the keys are correct but item_count and service are invalid, both field names appear in sorted order. These cases catch implementations that accidentally return the first value error found or change their response according to dictionary iteration order.

The supplied eighteen cases cover selected boundaries, option combinations, type mistakes, and validation ordering. They are a starting suite, not an exhaustive proof. Additional useful cases include a string amount, a null service, and an array where a scalar belongs. A coverage report should state which categories are present and which remain outside scope. Raw case count alone hides whether the collection has eighteen distinct purposes or eighteen versions of the same happy path.

4. Ask DeepSeek to propose cases within the contract

A good generation request names the function, provides the full contract, and lists coverage already present. Ask for a small batch that fills specific gaps. For example, after writing the fee-threshold cases yourself, request candidates involving JSON types and validation precedence. This makes the answer easier to inspect and reduces duplicate work. It also gives you a clear way to reject a suggestion that changes the requirements instead of testing them.

The prompt below asks for inputs and purposes only. It deliberately leaves expected results for a separate review step. You can request proposed expectations in a scratch conversation if that helps discussion, but do not copy them directly into the trusted suite. The final fixtures later in this article include reviewed expectations because a reusable test case needs both its input and the result against which execution will be checked.

You are proposing synthetic inputs for a fictional parcel-quote function.
Use only the written contract below. Do not invent customer records.
Return a JSON object with exactly two keys: candidates and questions.
Both values must be arrays. Each candidate has exactly:
  purpose: a string of 1..200 characters stating the behavior it would test
  input: the proposed object, including deliberate invalid values or keys if needed
Do not provide expected results. A separate review will assign them.

Contract:
- Exactly subtotal_cents, item_count, region, service are required.
- subtotal_cents: integer 0..1000000, excluding Boolean and decimal tokens.
- item_count: integer 1..50, excluding Boolean and decimal tokens.
- region: mainland or remote. service: standard or express.
- Base fees: standard 500 cents, express 1200 cents; remote adds 700.
- Free delivery only for mainland + standard + subtotal_cents >= 5000.
- Wrong keys: reject with only the keys error.
- Otherwise report all fields with invalid values, sorted by field name; do not coerce values.

Existing coverage: valid fee combinations and threshold neighbors.
Suggest at most six additional cases about types and validation precedence.
Avoid duplicate purposes. If any rule needed for a proposed case is ambiguous,
return candidates as [] and put the unresolved questions as strings in questions.
Otherwise return questions as []. Never label a question a fixture or invent policy.
Example successful candidate shape:
{"candidates":[{"purpose":"Boolean item count is invalid",
"input":{"subtotal_cents":2000,"item_count":true,
"region":"mainland","service":"standard"}}],"questions":[]}

Keep the generation schema different from the admitted-fixture schema when that distinction helps your workflow. The response can carry an unresolved question separately from its candidate array. An admitted case needs a stable identifier, an approved input, and a verified expectation. Preserving separate files prevents an unfinished answer from appearing test-ready simply because it already contains fields named “expected” and “confidence.” Naming a value does not establish its reliability.

As checked on October 3, 2026, DeepSeek’s official Chat Completions documentation lists deepseek-flash and deepseek-v4-pro. Its JSON Output guide uses response_format with type json_object, asks for a JSON instruction and an example format, and warns about occasional empty content. A response ending because of a length limit can be incomplete. Confirm the current documentation when integrating and reject empty or truncated candidates before trying to admit them.

JSON output controls the response format, not the truth of a delivery policy. A parseable record may contain a Boolean subtotal, a fictional extra option, or a purpose label that does not match its input. Use the site’s structured-output validation guide when building an API boundary, then add the task-specific checks described here. The tutorial itself does not require an API key, a paid request, or a particular reasoning configuration.

Six-step fixture admission path: written contract, required coverage, DeepSeek proposes inputs, human-reviewed expectations, local checks, then a frozen fixture suite. Failed candidates return to review; model suggestions cannot define expected results.
Admit fixtures only after expectations are reviewed and local checks pass. Failed candidates return to review; model suggestions never define expected results.

5. Review expected results independently

The test oracle is the basis for deciding whether the program’s answer is correct. For this small policy, a human-reviewed decision table is sufficient. At 4,999 cents, mainland standard costs 500. At 5,000 and 5,001, it costs zero. At 5,000, remote express costs 1,200 plus 700, or 1,900. These expectations are written into the fixture file before the implementation under test is run.

Do not generate the expected field by calling the same function you plan to test. That merely records what the function currently does, including any bug. A regression snapshot can intentionally preserve observed behavior, but it should be labeled as such and reviewed against the intended contract. When you want a correctness test, the expected result needs an independent justification, such as hand-worked examples, a reviewed rule table, or a separately maintained reference calculation.

A second implementation is not automatically independent. If both versions copy the same flawed comparison or use the same helper, agreement may repeat the same mistake. For a more complex system, review the reference calculation against a few simple anchor cases and document where it differs from production architecture. The important question is whether a defect in the production path could plausibly also determine the expected result.

Separate the expected outcome from the explanation. A purpose label such as “remote surcharge survives the threshold” tells a reviewer why a case exists. The assertion remains a concrete object containing a fee or a specific rejection. Long generated explanations should not be parsed as executable instructions or used as the source of numerical truth. Keep them as review notes, and shorten the final purpose until a future maintainer can understand it at a glance.

Use uncertainty as a reason to pause admission. If the model proposes a refund, a coupon, or an overnight service that is not in the contract, record it as a possible product question rather than adding a new expected behavior. A useful fixture suite is intentionally opinionated about approved requirements. Quietly expanding the policy because a generated example sounded reasonable makes the tests less trustworthy and can constrain later implementation work accidentally.

6. Run the complete offline fixture example

Save the two complete blocks below as fixture_demo.py and fixtures.json in the same disposable local folder. Run the displayed command with Python 3.10 or newer. The example and its independent checks were run with Python 3.12.14. No packages need to be installed. The first file contains a bounded JSON loader, fixture-envelope checks, and a small quote implementation. The second contains eighteen authored inputs and their reviewed expected outcomes. Neither file contacts DeepSeek or any delivery service.

Show complete fixture_demo.py
"""Offline, author-designed parcel-quote fixture demonstration (Python 3.10+).
Run: python3 -B fixture_demo.py fixtures.json
No network calls, model calls, credentials, or third-party dependencies.
The fictional fee policy is for testing only, not a real shipping service.
"""
import json
import re
import sys
from pathlib import Path

FIELDS = {"subtotal_cents", "item_count", "region", "service"}
MAX_BYTES = 65536


def unique_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("duplicate JSON key: " + key)
        result[key] = value
    return result


def reject_constant(value):
    raise ValueError("nonstandard JSON constant: " + value)



def validate_result(result, label):
    """Check result shape and exact types before ordinary dict comparison."""
    if type(result) is not dict:
        raise ValueError(f"{label} must be an object")
    if type(result.get("status")) is not str:
        raise ValueError(f"unknown {label} status")
    if result["status"] == "ok":
        if (set(result) != {"status", "fee_cents"}
                or type(result["fee_cents"]) is not int
                or not 0 <= result["fee_cents"] <= 10000):
            raise ValueError(f"invalid success {label}")
    elif result["status"] == "reject":
        fields = result.get("fields")
        if (set(result) != {"status", "fields"} or type(fields) is not list
                or not fields or any(type(x) is not str for x in fields)
                or any(x not in FIELDS | {"keys"} for x in fields)
                or fields != sorted(set(fields))
                or ("keys" in fields and fields != ["keys"])):
            raise ValueError(f"invalid rejection {label}")
    else:
        raise ValueError(f"unknown {label} status")

def load_fixtures(path):
    # Bounded reading avoids loading an oversized fixture before rejecting it.
    with open(path, "rb") as stream:
        raw = stream.read(MAX_BYTES + 1)
    if len(raw) > MAX_BYTES:
        raise ValueError("fixture file exceeds byte limit")
    doc = json.loads(raw.decode("utf-8"), object_pairs_hook=unique_object,
                     parse_constant=reject_constant)
    if type(doc) is not dict or set(doc) != {"schema_version", "cases"}:
        raise ValueError("invalid document envelope")
    if type(doc["schema_version"]) is not int or doc["schema_version"] != 1:
        raise ValueError("unsupported schema version")
    cases = doc["cases"]
    if type(cases) is not list or not 1 <= len(cases) <= 50:
        raise ValueError("expected 1 to 50 cases")
    seen = set()
    for case in cases:
        if type(case) is not dict or set(case) != {"id", "purpose", "input", "expected"}:
            raise ValueError("invalid case envelope")
        case_id = case["id"]
        if type(case_id) is not str or not re.fullmatch(r"FIX-[0-9]{3}", case_id):
            raise ValueError("invalid case ID")
        if case_id in seen:
            raise ValueError("duplicate case ID")
        seen.add(case_id)
        if type(case["purpose"]) is not str or not 1 <= len(case["purpose"]) <= 200:
            raise ValueError("invalid purpose")
        if type(case["input"]) is not dict:
            raise ValueError("input must be an object")
        validate_result(case["expected"], "expectation")
    return cases


def quote(payload):
    """A small implementation under test; never used to generate expectations."""
    if set(payload) != FIELDS:
        return {"status": "reject", "fields": ["keys"]}
    bad = []
    for key, low, high in (("subtotal_cents", 0, 1000000), ("item_count", 1, 50)):
        value = payload[key]
        if type(value) is not int or not low <= value <= high:
            bad.append(key)
    for key, allowed in (("region", ("mainland", "remote")),
                         ("service", ("standard", "express"))):
        if type(payload[key]) is not str or payload[key] not in allowed:
            bad.append(key)
    if bad:
        return {"status": "reject", "fields": sorted(bad)}
    fee = 500 if payload["service"] == "standard" else 1200
    if payload["region"] == "remote":
        fee += 700
    elif payload["service"] == "standard" and payload["subtotal_cents"] >= 5000:
        fee = 0
    return {"status": "ok", "fee_cents": fee}


def check_cases(cases, implementation=quote):
    failures = []
    for case in cases:
        actual = implementation(case["input"].copy())
        validate_result(actual, "result")
        if actual != case["expected"]:
            failures.append({"id": case["id"], "expected": case["expected"],
                             "actual": actual})
    if failures:
        raise AssertionError(json.dumps(failures, indent=2, allow_nan=False))
    return len(cases)


if __name__ == "__main__":
    if len(sys.argv) != 2:
        raise SystemExit("Usage: python3 fixture_demo.py fixtures.json")
    count = check_cases(load_fixtures(Path(sys.argv[1])))
    print(f"PASS: {count} authored fixtures match their reviewed expectations.")
Show complete fixtures.json: 18 authored cases
{
  "schema_version": 1,
  "cases": [
    {
      "id": "FIX-001",
      "purpose": "One cent below free-shipping threshold",
      "input": {
        "subtotal_cents": 4999,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 500
      }
    },
    {
      "id": "FIX-002",
      "purpose": "Exactly at free-shipping threshold",
      "input": {
        "subtotal_cents": 5000,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 0
      }
    },
    {
      "id": "FIX-003",
      "purpose": "One cent above free-shipping threshold",
      "input": {
        "subtotal_cents": 5001,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 0
      }
    },
    {
      "id": "FIX-004",
      "purpose": "Remote standard does not qualify for free shipping",
      "input": {
        "subtotal_cents": 5000,
        "item_count": 1,
        "region": "remote",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 1200
      }
    },
    {
      "id": "FIX-005",
      "purpose": "Mainland express does not qualify for free shipping",
      "input": {
        "subtotal_cents": 5000,
        "item_count": 1,
        "region": "mainland",
        "service": "express"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 1200
      }
    },
    {
      "id": "FIX-006",
      "purpose": "Remote express includes remote surcharge",
      "input": {
        "subtotal_cents": 5000,
        "item_count": 1,
        "region": "remote",
        "service": "express"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 1900
      }
    },
    {
      "id": "FIX-007",
      "purpose": "Minimum subtotal and minimum item count are valid",
      "input": {
        "subtotal_cents": 0,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 500
      }
    },
    {
      "id": "FIX-008",
      "purpose": "Maximum subtotal and maximum item count are valid",
      "input": {
        "subtotal_cents": 1000000,
        "item_count": 50,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "ok",
        "fee_cents": 0
      }
    },
    {
      "id": "FIX-009",
      "purpose": "Subtotal below allowed range",
      "input": {
        "subtotal_cents": -1,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "subtotal_cents"
        ]
      }
    },
    {
      "id": "FIX-010",
      "purpose": "Subtotal above allowed range",
      "input": {
        "subtotal_cents": 1000001,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "subtotal_cents"
        ]
      }
    },
    {
      "id": "FIX-011",
      "purpose": "Zero item count is invalid",
      "input": {
        "subtotal_cents": 4999,
        "item_count": 0,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "item_count"
        ]
      }
    },
    {
      "id": "FIX-012",
      "purpose": "Item count above maximum",
      "input": {
        "subtotal_cents": 4999,
        "item_count": 51,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "item_count"
        ]
      }
    },
    {
      "id": "FIX-013",
      "purpose": "Boolean subtotal must not become integer one",
      "input": {
        "subtotal_cents": true,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "subtotal_cents"
        ]
      }
    },
    {
      "id": "FIX-014",
      "purpose": "Decimal token is not an integer token",
      "input": {
        "subtotal_cents": 5000.0,
        "item_count": 1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "subtotal_cents"
        ]
      }
    },
    {
      "id": "FIX-015",
      "purpose": "Unknown region is invalid",
      "input": {
        "subtotal_cents": 4999,
        "item_count": 1,
        "region": "offshore",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "region"
        ]
      }
    },
    {
      "id": "FIX-016",
      "purpose": "Unexpected field is a keys error",
      "input": {
        "subtotal_cents": 4999,
        "item_count": 1,
        "region": "mainland",
        "service": "standard",
        "coupon": "FREE"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "keys"
        ]
      }
    },
    {
      "id": "FIX-017",
      "purpose": "All value errors are returned in sorted order",
      "input": {
        "subtotal_cents": 4999,
        "item_count": false,
        "region": "mainland",
        "service": "overnight"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "item_count",
          "service"
        ]
      }
    },
    {
      "id": "FIX-018",
      "purpose": "Missing field takes precedence over value validation",
      "input": {
        "subtotal_cents": -1,
        "region": "mainland",
        "service": "standard"
      },
      "expected": {
        "status": "reject",
        "fields": [
          "keys"
        ]
      }
    }
  ]
}
python3 -B fixture_demo.py fixtures.json

PASS: 18 authored fixtures match their reviewed expectations.

The successful output says that all eighteen authored fixtures match their reviewed expectations. That is evidence about these examples and this implementation. It does not establish full business coverage, production suitability, or the quality of any model’s generated cases. If you replace the quote function with your own adapter, preserve the fixture expectations and make the adapter return the same explicit result shape so discrepancies remain easy to inspect.

Try one controlled mistake to see the test fail. Change the free-delivery comparison from greater-than-or-equal to strictly greater than. The case at exactly 5,000 cents should fail while the neighboring threshold cases still explain the intended boundary. Restore the comparison afterward. Another useful mutation is to grant free delivery to every order at or above the threshold; the remote and express cases should expose that broader, incorrect interpretation.

Also test the test-data boundary. Duplicate a case identifier, replace an expected fee with true, or add the same JSON key twice in one object. The loader should reject those malformed fixtures before running the quote function. These checks protect the test harness from ambiguous inputs. They are different from valid negative tests, where the fixture itself is well formed and the embedded application input is deliberately invalid.

The loader uses a small maximum file size and case count to keep the example reviewable. Those limits are tutorial choices, not universal production recommendations. It is not a complete parser sandbox, a privacy scanner, or a resource-isolated execution system. If external parties can submit arbitrary documents or code to your infrastructure, use appropriate process isolation, resource limits, and a separately reviewed ingestion design rather than extending this example by assumption.

7. Keep fixture validity separate from input validity

There are two boundaries in this workflow. The fixture envelope must be valid enough for the harness to understand it. The embedded application input may be valid or invalid according to the test’s purpose. Confusing these boundaries causes a common mistake: filtering out every invalid application input before testing. That removes precisely the negative cases that verify whether your product rejects malformed requests correctly.

In the tutorial, each case needs an identifier, a bounded purpose string, an input object, and a correctly shaped expected result. A rejection expectation lists known field names in sorted, unique order; a keys error must appear alone. The input object is allowed to contain missing keys, unexpected keys, or invalid values because those are legitimate test subjects. The quote function evaluates those values; the fixture loader does not silently repair them before execution.

Parsing also needs explicit choices. Python’s default JSON decoder accepts certain nonstandard numeric constants and keeps the last value when an object repeats a name. The loader supplies callbacks to reject both situations. This prevents a fixture from looking like one thing to a reviewer and behaving like another after decoding. The separate exact-type checks prevent a Boolean from passing as an integer fee or schema version.

Be careful with equality at the comparison boundary as well. Different programming languages and test frameworks may compare numeric and Boolean values differently. Our admitted expectations require true integer fee values, and the runner validates the shape and exact types of actual results before comparing them. That prevents a returned Boolean or decimal fee from passing through Python’s numerical equality rules. Preserve this output check when adapting the harness to another implementation; equal-looking values do not always satisfy the same output contract.

Report failures at the right stage. “Malformed fixture envelope,” “application result differs from expectation,” and “coverage category is missing” are different problems with different owners. The sample runner reports mismatched cases with their identifiers, expected objects, and actual objects. A larger pipeline should preserve those distinctions so a dataset formatting error does not look like a product regression or disappear as an unexplained skipped test.

8. Add realism only where it tests a behavior

A shipping-fee function does not need names, street addresses, biographies, or realistic purchase histories. Adding them increases review work without changing its four-field contract. If you are testing a user interface, however, long labels, non-Latin text, and missing optional fields may be essential. Add each realistic feature because it exercises something observable: wrapping, sorting, serialization, search, or validation.

For text-heavy fixtures, give DeepSeek specific dimensions rather than asking it to imitate a real customer. You might request a short product title, a long title with punctuation, and a right-to-left title with an explicit locale. Verify byte length, display behavior, and normalization separately where those affect the application. The product localization guide explains related checks for placeholders and product text that must survive translation.

Relationship-heavy datasets need another layer of design. If an order references a customer identifier, ensure the customer exists in the fixture set. If line totals are supposed to sum to the order subtotal, calculate that relationship deterministically after generating the individual values. Prefer a small local builder for foreign keys and arithmetic instead of relying on a model to maintain hundreds of interdependent rows consistently.

Distribution is a separate decision from correctness. A deliberate boundary suite may contain far more invalid requests and rare option combinations than production traffic. That is appropriate for finding logic errors but misleading if you use it to estimate average latency or customer behavior. Keep functional, demonstration, and load datasets separate, and record their intended use so someone does not mistake a stress-oriented collection for a representative population.

Dates require similar precision when your own domain includes them. Fix the relevant “as of” date rather than letting fixtures depend on today. State the accepted date syntax and the policy for month ends, leap days, and time zones. Python date parsing can accept forms beyond a simple YYYY-MM-DD string, so validate the textual contract as well as whether a date exists. A library can calculate a date; it cannot choose your product’s anniversary policy.

9. Keep fictional data fictional and the environment isolated

The easiest dataset to review for this example is one that never starts with customer records. Write the business rules in generic terms and invent the values directly. Replacing names in copied support tickets would still leave order details, unusual incidents, or other identifying context in the text. Calling that output synthetic would not demonstrate that it was safe to share with a model or publish in a repository.

Review the specification itself before sending it to a hosted service. Private pricing rules, internal field names, unreleased features, and examples copied from incident reports can reveal information even when no personal names appear. Follow your organization’s approved destinations and data-handling process. The API data-minimization guide provides a broader workflow for deciding what should leave an application boundary.

If a fixture genuinely requires an email-shaped value, use a documentation domain such as example.com rather than inventing a plausible address at a random domain. IANA maintains example domains for illustrative use. Even then, disable or stub the email adapter in tests. A safe-looking destination string is not an isolation mechanism, and the example domain’s website is not a service dependency for your application.

Mark test records visibly and structurally. Use identifiers such as FIX-001 or an explicit environment field where the real schema permits it. Keep test credentials, storage, message queues, and outbound adapters separate from production. A generated order must not accidentally trigger a shipment, a notification, or an invoice merely because it passed a schema check. The fixture content and the execution environment both need deliberate boundaries.

Finally, prevent test data from leaking into unrelated evaluation claims. A model that helped generate a dataset may have shaped its wording, topic distribution, and error patterns. Doing well on that dataset does not establish performance on unseen real-world inputs. Maintain independently selected evaluation examples when measuring a model or product, and describe how each dataset was created. The provenance is part of interpreting the result, not administrative decoration.

10. Freeze accepted fixtures and review changes like code

Once a case is accepted, save the exact reviewed artifact. Do not regenerate the entire suite from a prompt on every build. A saved fixture is a reproducible input; a new model response is another candidate that needs review. Record the contract version, generation prompt if one was used, model identifier and relevant settings, admission date, and the reason each case was added.

A lower sampling temperature is not a substitute for keeping the bytes you tested. Model services, defaults, and surrounding prompts can change, and a future request may produce a different dataset. Ordinary regression tests should execute the frozen fixtures without needing a model service to be available. Keep optional model-assisted exploration in a separate workflow so an external timeout does not make a deterministic unit test appear flaky.

When the policy changes, update the contract first and identify exactly which cases should change. If the free-delivery threshold moves, the old boundary cases may still be useful historical examples, but the new boundary requires its own neighboring values. Review the fixture diff alongside the implementation diff. A large unexplained replacement of expected results can hide an accidental behavior change behind the appearance of refreshed data.

Track three small sets: accepted fixtures, quarantined candidates, and retired fixtures with their reasons. Quarantine is useful for a case with a good idea but an unresolved expectation. Retirement is appropriate when a requirement disappears or a fixture duplicates an existing check without adding clarity. Neither status should silently count as passing coverage. A reviewer should be able to tell which cases actually protect the current contract.

Use a lightweight maintenance signal such as required coverage categories present, fixtures rejected at admission, or new defects exposed by accepted cases. Avoid declaring that the suite is “high quality” because the model generated a large batch quickly. For broader prompt changes, the prompt regression testing guide explains how to compare revisions against a stable evaluation set. Here, the priority is keeping the fixture contract understandable and its assertions independent.

11. A practical first session

Begin with one small function whose behavior you can calculate without a model. Write its accepted fields, ranges, option combinations, and error policy. Manually create a few normal cases and the most important boundary neighbors. Then ask DeepSeek for a short list of missing situations, inspect each suggestion, and admit only the ones whose purpose and expected result you can explain.

Run the resulting suite against the implementation and against one deliberately broken variation. If the mutation survives, investigate whether the relevant case is missing, the assertion is weak, or the change is actually allowed by the contract. This exercise checks the usefulness of your tests directly. It is often more revealing than adding another hundred generated records that all resemble inputs you already cover.

  • Define the dataset’s intended use and exclusions
  • Write the application contract and validation order
  • Choose boundaries, type cases, and option combinations
  • Ask DeepSeek for candidate inputs and concise purposes
  • Review expected outcomes using an independent source of truth
  • Reject malformed fixture envelopes while preserving intentional negative inputs
  • Run locally with outbound side effects disabled
  • Freeze reviewed files, record provenance, and review future diffs

The central habit is simple: treat generated records as proposals until their role in a test is clear. DeepSeek can help widen your search for useful cases, while contracts, reviewed expectations, and deterministic checks make those cases dependable. A compact suite that catches an off-by-one threshold or a type error gives you a concrete result. That is a stronger foundation than a large dataset whose realism nobody can verify.

Sources & References

Primary documentation checked on October 3, 2026. The fictional delivery policy, prompts, code, fixture values, and workflow recommendations are original tutorial material. The sources below support the API, language, domain, and test-design facts; they do not endorse this example or establish model performance.

  1. DeepSeek: Chat Completions API reference — current model identifiers, response formats, and finish reasons
  2. DeepSeek: JSON Output guide — JSON-mode instructions and empty-content caveat
  3. Python: JSON encoder and decoder — duplicate names, numeric constants, decoder callbacks, and resource caution
  4. Python: Boolean type and built-in numeric types — Boolean and integer type relationship
  5. Python: Date objects — date validation and accepted ISO formats
  6. IANA: Example domains — documentation domains and service limitations
  7. ISTQB: Foundation Level syllabus v4.0.1 — equivalence partitioning, boundary-value analysis, and decision-table testing
Shares:
2 Comments
Leave a Reply

Your email address will not be published. Required fields are marked *