Evals vs unit tests

A unit test asserts an exact result from deterministic code. An eval measures how well a non-deterministic system performs across a set of cases and returns a score. You need both, for different parts of the system.

Short answer

Unit tests still apply to almost everything you wrote: parsing, schema validation, retries, tool implementations, prompt assembly, cost accounting. What they cannot do is assert equality on generated text, because the same input can legitimately produce different output. That is what evals are for. An eval runs a fixed set of cases, grades each one against a criterion, and reports a score and a distribution rather than a pass or a fail. The gate is a threshold you chose in advance, not a green tick.

Teams arriving from ordinary software engineering usually try one of two things first, and both fail in instructive ways. The first is to write unit tests over model output, asserting that a given prompt returns a given string. These pass on the day they are written and then fail for reasons unconnected to quality, so they get muted, and the system ends up with less coverage than if they had never existed. The second is to abandon automated checking entirely and rely on someone reading the output before release, which does not survive contact with a change that alters behaviour subtly across a thousand cases.

The resolution is not a better assertion library. It is accepting that the thing under test is a system whose output is a distribution rather than a value, and that the honest measurement of a distribution is a score over a sample. That reframes several habits at once. A single failing case is no longer conclusive; a mean is no longer sufficient; and the set of cases becomes an asset in its own right, more valuable and harder to rebuild than the harness that runs it.

None of this displaces unit tests. Most of a production system is ordinary software, and ordinary software should be tested the ordinary way.

Unit tests vs Evals, side by side

Unit testsEvals
What it assertsThis input produces exactly this outputThis set of inputs scores at or above this threshold
Result shapePass or failA number, plus a distribution and a set of cases that moved
DeterminismRequired. Flakiness is a defect.Not available. Variation is the property being measured.
What it protectsThe code you wroteThe behaviour of the system as a whole
Cost to runMilliseconds, effectively freeModel calls, money and minutes, so it runs on a schedule rather than on every save
When it runsEvery commitEvery change to a prompt, model, tool or retrieval step, against a fixed set
What a failure tells youA specific line of code is wrongSomething moved. Finding out what is the next piece of work.

Non-determinism is the whole reason evals exist

Two runs of the same prompt can produce different wording, different ordering and different levels of detail while both being correct. Equality assertions treat every one of those differences as a defect, so they generate failures that carry no information, and a suite that cries wolf gets disabled.

The move that fixes it is to assert a property rather than a value. Did the answer extract the right identifier. Does it validate against the schema. Does it cite a source that exists. Does it decline where declining is correct. Each of those is checkable without pinning the wording, and each survives a rephrasing that a string comparison would have failed.

Three ways to grade, and when each is honest

Programmatic grading is first choice wherever it applies: exact match on an extracted field, a classification label, schema validity, presence of a required citation, a numeric tolerance. It is cheap, deterministic and beyond argument, and a surprising amount of real work reduces to it.

Model-as-judge covers what code cannot check, such as whether an answer is well reasoned or appropriately hedged. It is legitimate, with two conditions: the judge needs an explicit rubric rather than a general instruction to rate quality, and it must be validated against human labels on a sample so you know how far to trust it. Human grading is the expensive reference the other two are calibrated against, and it is what you use to build and periodically recheck the set.

The set of cases is the asset

The harness is a weekend of work. The set is a year of paying attention, and it is what actually makes the numbers mean anything.

Build it from real traffic and real failures rather than from invented examples, because invented cases cluster around the behaviour you already anticipated. Every production surprise should end up in it, with the expected behaviour written down while the incident is fresh. Then hold it fixed, so scores are comparable across runs, and version it when it genuinely has to change. A set that quietly grows between runs produces a moving score that nobody can interpret, which is worse than no score at all.

An eval that only reports is not a gate

The step teams skip is committing to a threshold in advance. Without one, every result is negotiable after the fact, and a score that drifts down two points per release passes indefinitely because no single release looks bad.

Decide before the run what score is acceptable, and what happens when it is not met. Then pair the aggregate with a regression set of cases that must not fail at all, typically ones that come from real incidents. That combination is what makes the eval load-bearing: the aggregate catches broad degradation, and the regression set catches the specific failures you have already promised somebody would not recur.

Most of the system is still ordinary software

It is worth being concrete about how much of a production system unit tests still own, because the eval conversation tends to crowd them out. Prompt assembly, retrieval query construction, schema validation of structured output, parsing and the error path when parsing fails, retry and backoff behaviour, tool implementations, cost accounting, rate limit handling, and the branch on stop reason before anything is parsed at all.

Every one of those is deterministic and should be tested in milliseconds on every commit. Evals sit above them and measure what happens when a non-deterministic component is placed in the middle. A team with excellent evals and no unit tests will still ship a crash on a truncated response.

How to choose

Reach for unit tests when

  • The code under test is deterministic, which covers most of the system
  • You are checking parsing, validation, retries, tool implementations or prompt assembly
  • You need the check to run on every commit at no cost
  • A failure should point at a specific line rather than at a trend

Reach for evals when

  • The output is generated, so the same input can legitimately vary
  • You are about to change a prompt, a model, a tool or a retrieval step
  • You need to know whether quality moved, and by how much, not whether one case passed
  • You want a threshold that blocks a release, backed by a regression set of known failures

Where candidates go wrong

Trap 1: assert the exact string and call it a test

It is the natural first attempt and it produces the worst outcome available, because the test fails on rephrasings that are perfectly correct and passes on answers that are subtly wrong but happen to match. The team learns that the suite is noise and stops trusting it. The correct answer asserts a property: an extracted value, a label, schema validity, the presence of a citation, a refusal where refusing is right. Options that propose pinning generated text, or that propose fixing flakiness by lowering variability until the string is stable, are treating non-determinism as a defect rather than as the thing being measured.

Trap 2: ask a model whether the answer was good

Model-as-judge is a legitimate technique that becomes a distractor when it arrives unqualified. A judge with no rubric, applying its own notion of quality, produces a fluent number with no established relationship to what you care about, and it can be wrong in a correlated way across the whole set. Two conditions make it defensible. The rubric has to be explicit, naming what counts and what does not. And the judge has to be validated against human labels on a sample, so its agreement rate is known. Where a programmatic check is available, prefer it: a judge asked to assess whether JSON is valid is a slower, costlier and less reliable parser.

Trap 3: one number is enough

A mean hides the shape of the change, and the shape is usually where the information is. An average that holds steady can conceal a version that improved on easy cases and collapsed on hard ones, which is a materially worse system for the users who needed it most. Look at the distribution and at which specific cases changed direction. A release that improves the aggregate while regressing a case drawn from a real incident is not an improvement, which is exactly why the regression set sits alongside the score rather than inside it.

Trap 4: build the eval set once the product stabilises

The set is assembled from failures, and failures happen most in the period this reasoning proposes to skip. Deferring it discards the only data that would have made it good, and it removes the baseline you need to tell whether a later change helped. The cheap version is genuinely cheap: twenty real cases with expected behaviour written down, graded programmatically where possible, run whenever a prompt changes. That is enough to catch the large regressions, and it grows naturally because every incident adds a case. Waiting for a mature harness usually means never having one.

How the exam tests it

Evaluation, Testing and Optimization is 16% of the CCAR-P blueprint, roughly 10 of the 63 scored questions. The Professional-level framing matters here: questions are less about whether to evaluate and more about choosing a grading method that is honest for the claim being made, and about what makes an eval a release gate rather than a dashboard.

Common questions

What is the difference between an eval and a unit test?

A unit test asserts that deterministic code produced an exact result, and returns pass or fail. An eval runs a fixed set of cases through a non-deterministic system, grades each against a criterion, and returns a score and a distribution. They cover different parts of the system and you need both.

Can I unit test model output?

You can test properties of it, not its exact text. Assert the extracted value, the classification label, schema validity, the presence of a citation, or a refusal where refusing is correct. Pinning the wording produces failures that carry no information, and a suite nobody trusts gets muted.

Is using a model as a judge legitimate?

Yes, with two conditions. The judge needs an explicit rubric rather than a general instruction to rate quality, and it must be validated against human labels on a sample so its agreement rate is known. Where a programmatic check will do the job, prefer it, because it is cheaper and beyond argument.

How many cases does an eval set need?

Fewer than teams expect to start with. Twenty real cases with expected behaviour written down, graded programmatically where possible, will catch large regressions and give you a baseline. What matters more than size is that the cases come from real traffic and real failures, and that the set stays fixed so scores remain comparable.

What makes an eval a release gate rather than a report?

A threshold chosen before the run, and a regression set of cases that must not fail at all. Without a committed threshold every result is negotiable afterwards, which lets quality drift down a little per release while every individual release looks acceptable.

Do evals replace unit tests?

No. Prompt assembly, parsing, schema validation, retries, tool implementations, cost accounting and the branch on stop reason before parsing are all deterministic and belong in fast unit tests on every commit. Evals measure what happens when a non-deterministic component sits in the middle of that system.

Practise this

Evaluation, Testing & Optimization is 16% of the CCAR-P blueprint, and the bank is weighted to match. Every option carries a written explanation, not just the correct one, so a distinction like this one is explained where you get it wrong.

See CCAR-P

Other CCAR-P distinctions

Not affiliated with or endorsed by Anthropic. Domain names and weightings are taken from the published exam guide; always check the official guide before booking.