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 give the full picture.
What you need
- The Emolysis desktop app or the
emocommand 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 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 shape and shows the slots it filled:
- Key columns:
customer_id. - Ordering columns for "latest wins":
updated_at, then a tie-breaker such assource_row_id. - Type map:
customer_idas integer,updated_atas 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_atvalues; customer 2 appears twice with the sameupdated_at; customer 3 hascustomer_idarriving 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, or the answer to what a golden test is.