The parts of a Claude-integrated feature that are deterministic — request construction, response parsing, tool execution, error handling, the retry and caching logic from earlier lessons — are unit-testable exactly like any other code, and should be, independent of the model itself. Mock the API boundary for these tests: assert your code builds the right request (correct system placement, correct tool_choice, correct cache_control position) and handles a given canned response correctly (correct block-type dispatch, correct tool_use_id matching, correct handling of an unexpected stop_reason), without making a real network call for every test run. Fast, deterministic, and they run in CI on every commit.
Testing the model's behaviour, not just your code
Whether Claude's actual output meets a quality bar is a different kind of test — not a pass/fail unit test but an evaluation against a curated set of representative inputs with a grading rubric (Domain 8 goes deeper on building that harness). Conflating the two — asserting exact string equality on live model output in a CI unit test — produces a flaky, low-value test that breaks on any harmless phrasing change, forcing a developer to either loosen the assertion until it's meaningless or babysit the test every time the wording shifts.
What to assert on non-deterministic output
When a test does need to touch live or recorded model output, assert structural and semantic properties instead of exact text: does the response contain a valid JSON object matching the expected schema, does a required field exist and pass a type check, does the answer contain a specific fact or number regardless of surrounding phrasing, does a classification land in the expected category. This is a weaker but far more durable assertion — it survives the model rephrasing an answer while still catching a genuine regression, like a missing required field or a wrong category.
Common exam distractor
Asserting an exact string match against live Claude output in an automated test suite is a trap answer. Non-deterministic generation means the same prompt can validly produce differently-worded output; test structure and correctness properties, not exact wording.
Recorded fixtures as a middle ground
A useful middle ground between a fully mocked unit test and a live model call on every CI run is a recorded fixture: capture a real response once, save it as a canned payload, and replay it against your parsing/handling code in fast, deterministic tests. This tests your code's handling of a realistic response shape without paying for or waiting on a live call every run, though it's worth periodically refreshing fixtures so they don't drift silently out of sync with what the live API actually returns as models and response shapes evolve.
Evaluation harnesses and LLM-as-judge
A quality evaluation needs a way to score an open-ended answer at scale, and one common approach is using a separate Claude call as a grader — feeding it the original prompt, the candidate response, and a rubric, and asking it to score or pass/fail the response against that rubric. This scales far better than manual review of every case, but it introduces its own reliability question: the grading prompt itself needs validation (does it agree with a human's judgment on a sample of cases?), and it's worth remembering the grader is itself a non-deterministic model call, which is why eval scores are usually reported as a pass rate across many cases rather than trusted on any single case in isolation.
Curating a golden dataset
An eval set's value depends heavily on what it covers: a handful of easy, typical-case prompts will pass cleanly on almost any reasonable model configuration and catch nothing. A useful golden dataset deliberately includes edge cases the application has actually failed on before (regression cases), ambiguous inputs where the right behaviour is a judgment call, and adversarial or malformed inputs the feature needs to handle gracefully rather than crash on. Building this set is itself an ongoing process — every real production failure is a candidate to add as a new eval case, so the dataset grows to reflect the actual failure modes the application has encountered rather than staying frozen at whatever the team thought to test on day one.
Key concept
A one-line rule of thumb the exam rewards: if a test needs to be re-recorded or hand-tuned every time the model's wording changes, it's testing the wrong thing. Structural and behavioural properties survive rephrasing; exact text doesn't.