# Your first golden test on DuckDB

> A preview of writing fixtures and an expected output for a dedupe pipeline, running them on DuckDB, and fixing a red test.

Golden tests are how Emolysis proves a pipeline before it deploys. This tutorial walks through one by hand, so the idea is concrete before you rely on the agent to write them. The [golden tests docs](https://emolysis.com/docs/golden-tests) give the full picture.

## What you need

- The Emolysis desktop app or the `emo` command line.
- A project created with `emo init customers`.
- An Emolysis account, signed in once in the app or with `emo login`; the Free plan is one.
- No platform. Everything here runs on [DuckDB](https://emolysis.com/platforms/duckdb) on your machine.

## Step 1: Describe the pipeline

Ask the agent: "Deduplicate the customers table to one row per customer id, keeping the most recently updated row." The agent picks the [Dedupe / conform](https://emolysis.com/shapes/dedupe-conform) shape and shows the slots it filled:

- Key columns: `customer_id`.
- Ordering columns for "latest wins": `updated_at`, then a tie-breaker such as `source_row_id`.
- Type map: `customer_id` as integer, `updated_at` as timestamp.

The tie-breaker matters. Without it, two rows with the same `updated_at` could swap between runs, and the output would not be deterministic.

## Step 2: Look at the fixtures

Emolysis adds a test case under `tests/` with two parts:

- **Input:** a small table with the hard cases for this shape. For example, customer 1 appears three times with different `updated_at` values; customer 2 appears twice with the same `updated_at`; customer 3 has `customer_id` arriving as text in one row.
- **Expected output:** exactly one row per customer: the latest row for customer 1, the row with the higher tie-breaker for customer 2, and customer 3 cast to an integer.

Fixtures are usually small Parquet files. You can open them in the app as tables.

## Step 3: Run the test

Run the tests from the app, or with the command line, for example `emo run template.test --params '{"pipeline": "pipelines/customers_dedupe"}'`. The parameter names here are illustrative.

The test runs the pipeline on DuckDB against the input and compares the result with the expected output, row for row. It should pass in seconds.

## Step 4: Break it on purpose

Edit the pipeline's slots and remove the tie-breaker, leaving only `updated_at`. Run the tests again. The result for customer 2 now depends on the run, and when it differs from the expected row, the test fails with the differing rows shown side by side.

In normal use, this is where the agent takes over: a red test sends it back to the template fill. It reads the failure, restores a deterministic ordering, and runs the tests again. You see each attempt.

## Step 5: Add your own case

Golden tests get better with the cases that hurt you before. Add a row to the input that once broke a real pipeline, for example a customer id with surrounding spaces, and add the row you expect to the output. Run the tests. If the template does not handle it, ask the agent to extend the conform rules and run them again until green.

## Step 6: Keep fixtures synthetic

Fixtures are committed to your repository and run in CI, so everyone with access can read them. Use invented values. If you want to see the pipeline on real data, pull a sample into the project's local lakehouse instead; samples are for looking, fixtures are for proving.

## What you learned

- A golden test is a fixed input, an expected output and an exact comparison.
- Good fixtures are built around the shape's hard cases, not the happy path.
- DuckDB makes the tests fast enough to run on every save.
- Red goes back to the template; only green can deploy.

For the reasoning behind this loop, read the post [tests before production](https://emolysis.com/news/tests-before-production), or the answer to [what a golden test is](https://emolysis.com/faq/what-is-a-golden-test).

---

Page: https://emolysis.com/tutorials/first-golden-test-on-duckdb. Emolysis is a product of Bandpey GmbH, Munich, Germany. It is in private development, and nothing is released yet.
