Unit Testing Tool Calls and Agent Logic Without Mocking Everything

Effective agent tests are harder to write than application tests because nondeterminism is a first-class feature. Strategies for making tests reliable without over-mocking the model.

AgentixForce Team··11 min read

Why Agent Tests Are Different

Testing a traditional API endpoint is straightforward: you send a fixed input and assert on a deterministic output. Agent testing breaks both of those assumptions. The model's output varies between runs even for identical inputs. The agent's behavior is emergent, it depends on the interaction between the prompt, the model's weights, and the tools available. You cannot write assertEqual(agent.run(task), expected_output) and expect it to pass reliably.

This doesn't mean agent testing is impossible, it means you need a different mental model. Instead of testing exact outputs, test behaviors. Instead of testing deterministic sequences, test invariants. Instead of asserting on the LLM's reasoning, assert on the structural properties of what it produces.

The Three Sources of Agent Non-Determinism

  • Sampling temperature: Even at temperature=0, many models are not guaranteed to produce identical outputs on repeated calls due to hardware floating-point differences and batching effects.
  • Model updates: Provider model updates (even patch versions) can change behavior. A test passing today may fail next week because the model's behavior shifted.
  • Tool output variability: Real-world tools return different data over time. A web search from yesterday returns different results today.
Agent Testing PyramidHeavier investment at the base — fast, cheap, high coverageE2E / Human EvalFull task runs · manual review10%Integration TestsMulti-tool flows · real APIs20%Eval HarnessLLM-as-judge · golden outputs30%Unit TestsTool schemas · prompt logic · parsers40%Slow, expensiveFast, cheapCoverage vs Cost MatrixUnitCov 90%Eval HarnessCov 75%IntegrationCov 55%E2ECov 30%
The Agent Testing Pyramid. Unit tests form the wide base, fast, cheap, and covering the most cases. The pyramid narrows upward through eval harness, integration, and E2E layers where tests are slower and more expensive but closer to production reality.

The Agent Testing Pyramid

The classic testing pyramid applies to agents, but the layers have agent-specific meanings. A well-structured agent test suite invests most heavily in unit tests at the base, uses an eval harness for semantic correctness, and reserves expensive integration and E2E tests for critical flows.

Layer 1, Unit Tests (40% of test effort)

Unit tests in an agent context test components that don't require a live LLM call. Tool schemas, parameter parsers, output formatters, budget managers, context assemblers, and prompt template renderers all have deterministic logic that can be tested conventionally. These should make up the majority of your test suite: they're fast (milliseconds), cheap (no API calls), and stable (no non-determinism).

Layer 2, Eval Harness (30% of test effort)

The eval harness runs real LLM calls against a curated set of tasks and scores the outputs using automated metrics: semantic similarity to golden answers, entity recall, tool selection correctness, and format compliance. This is where you catch behavioral regressions caused by prompt changes or model updates. Run on every PR, but cache LLM responses to control cost.

Layer 3, Integration Tests (20% of test effort)

Integration tests run the full agent against real tools (or high-fidelity sandboxed versions). They verify that the agent correctly orchestrates multi-tool workflows, handles tool errors, and produces outputs that satisfy end-to-end task requirements. These run nightly or on release candidates, not on every commit.

Layer 4, End-to-End / Human Eval (10% of test effort)

Full task runs with human reviewers or a strong LLM judge scoring output quality on a multi-criteria rubric. Expensive, slow, but the only way to catch subtle quality degradations that automated metrics miss. Run before major releases and when the eval harness shows ambiguous results.

What to Unit Test in an Agent

Many teams skip unit testing for agents because 'the interesting behavior comes from the LLM.' This is a mistake. A large fraction of agent failures come from deterministic code around the LLM: parsing tool calls, assembling context, enforcing budgets, routing decisions, output formatting.

High-Value Unit Test Targets

  • Tool schema validation: Every tool's JSON schema should be tested with valid inputs, invalid inputs, and boundary values. A schema that rejects valid parameters silently fails tasks.
  • Prompt template rendering: Variables injected into prompt templates (task description, user name, context snippets) should produce exactly the right output. Test all template variables with representative values and edge cases (None, empty string, very long strings).
  • Context assembler: Given a fixed set of messages and a token budget, verify the assembler produces a context of exactly the right size with the correct priority ordering.
  • Tool router: If your agent uses a router to decide which tool to call, test the routing logic with representative queries. Verify each routing rule selects the right tool.
  • Output parser: Parse tool call JSON from model output. Test with well-formed JSON, malformed JSON, truncated JSON, and JSON with extra fields.
  • Budget manager: Token counting and budget zone classification are deterministic. Test that zone thresholds trigger at exactly the right utilization percentages.

Handling Non-Determinism

When you can't avoid testing against the LLM directly, you need strategies for making those tests meaningful despite non-determinism. There are four primary approaches, each suited to different test scenarios.

Handling Non-Determinism in Agent TestsSemantic EquivalenceRun test N times (N=5–20)Embed all outputsCheck centroid similarityPass if avg sim > thresholdBehavioral ContractsDefine invariants (not exact text)e.g. 'must call search tool'e.g. 'answer mentions date'Assert on structure/content🌡Temperature PinningSet temperature=0 for testsSeed random state if availableUse deterministic samplingAccept: still not 100% stable⚖️LLM-as-Judge ScoringPass output to judge modelJudge scores 1–5 on criteriaTest passes if score ≥ 4Averages over multiple runs
Four strategies for handling LLM non-determinism in tests. Semantic equivalence checks run the test N times and verifies outputs cluster in embedding space. Behavioral contracts assert on structural invariants. Temperature pinning maximizes reproducibility. LLM-as-judge scores quality on a rubric.

Strategy 1, Semantic Equivalence

Rather than asserting the exact output text, embed the model's output and compare its cosine similarity to the golden answer embedding. Set a threshold (typically 0.85–0.92) above which the test passes. This tolerates paraphrasing while catching responses that are semantically wrong. Run the test 3–5 times and average the similarity scores to reduce sensitivity to a single unlucky sample.

Strategy 2, Behavioral Contracts

Define what the output must contain or do, not what it must say. For a customer support agent: the response must include the order number (entity assertion), must not include competitor names (negative assertion), and must call the check_order tool exactly once (structural assertion). These contracts are stable across model updates because they test behaviors, not phrasing.

Strategy 3, Temperature Pinning

Set temperature=0 for all test runs. Most models are more stable at temperature=0, though not perfectly deterministic due to hardware factors. Temperature pinning reduces, but does not eliminate, output variance. Combine with retry logic: if a test fails once at temperature=0, re-run it twice before marking it as a failure.

Tool Call Testing Strategies

Tool calls are the primary side-effectful operations an agent performs. Testing them requires distinguishing between what you're actually trying to test: the agent's decision to call a tool vs the tool's implementation vs the agent's use of the tool's result.

Mock vs Real Tool Testing StrategiesMock-Based TestingSpeed< 10ms per test🎛️ControlDeterministic outputs💰CostZero API spend⚠️RiskDiverges from real API📋Best forSchema · parsing · routingReal Tool Testing🐢Speed100ms–5s per test🎯FidelityActual API behavior💸CostAPI spend appliesRiskCatches integration bugs📋Best forAuth · rate limits · errorsVS
Mock vs real tool testing. Mocked tools are fast, free, and deterministic, ideal for testing the agent's decision-making. Real tools catch integration bugs but are slow and cost money. Use mocks for unit tests and real tools for integration tests.

What Mock Testing Gets Right

Mock testing is correct for verifying that the agent calls the right tool with the right parameters when given a specific task. You don't need the real API to test that 'when asked for a product price, the agent calls get_price(product_id=X)'. The decision logic is in the model and prompt, which you can test in isolation from the live tool.

What Mock Testing Gets Wrong

Mock testing misses failure modes that only appear with real tools: authentication errors, rate limit handling, unexpected response schema changes, network timeouts, and empty result sets. These failure modes cause agent misbehavior in production that mock tests never surface. Dedicate a portion of your integration test suite to real tool calls specifically to catch these.

Testing Error Handling

Error handling is an often-neglected dimension of tool call testing. What does the agent do when a tool returns an error? What if the tool times out? What if the result is empty? Build explicit test cases for each error type your tools can produce. Inject these errors into mock responses and verify the agent responds gracefully, retries where appropriate, falls back to alternatives, or surfaces a clear error to the user.

Prompt-Level Unit Tests

Individual prompt components can be tested in isolation before composing them into the full system prompt. Prompt-level testing catches errors in individual capability instructions before they interact with other components and produce confusing emergent failures.

Capability Isolation Tests

Test each section of your system prompt independently. The tool use section: does the model call tools when instructed to? The refusal policy: does the model refuse prohibited requests? The output format instructions: does the model produce the specified JSON structure? Isolation makes it easy to identify which prompt section is responsible when behavior breaks.

Prompt Section Interaction Tests

After testing sections in isolation, test their interactions. Two individually correct prompt sections can conflict with each other. For example, 'be concise' and 'always include a bulleted summary' may produce inconsistent behavior when both are active. Interaction tests catch these emergent conflicts before they reach users.

Behavioral Contracts Over Exact Match

The highest-leverage shift in agent test philosophy is moving from exact-match assertions to behavioral contract assertions. This shift makes tests significantly more stable, more meaningful, and easier to maintain.

Defining Behavioral Contracts

  • Structural contracts: Output must be valid JSON. Response must contain sections [introduction, analysis, recommendation]. Tool must be called before response is generated.
  • Positive content contracts: Response must mention the customer's name. Answer must include a date. Recommendation must reference the user's stated constraint.
  • Negative content contracts: Response must not mention competitors. Output must not contain PII. Answer must not contradict the data in the tool result.
  • Behavioral sequence contracts: Agent must call search before summarize. Agent must not call delete without prior confirmation. Agent must complete all sub-tasks before final report.
  • Quantitative contracts: Response must be between 50 and 500 words. Agent must not make more than 5 tool calls per task. Latency must be under 10 seconds.

Test Data and Fixture Management

Agent test suites need well-managed test data: task inputs, golden outputs, tool response fixtures, and adversarial inputs. Poor test data management is one of the most common reasons agent test suites become unreliable over time.

Golden Output Management

Golden outputs should be stored in version control alongside the code. When you deliberately change agent behavior, update the golden outputs as part of the same PR. This makes behavioral changes visible in code review. Commit semantically meaningful golden outputs, not arbitrary responses, but responses that represent the ideal answer to the test task.

Tool Response Fixtures

For tests that use mock tools, capture and store real tool responses as fixtures. When the real tool returns a new response shape (due to an API update), update the fixtures. This keeps mock behavior aligned with reality. Tag fixtures with the date they were captured and refresh them quarterly or when the tool API updates.

Task Bank Construction

Build your task bank from three sources: representative production tasks (sampled and anonymized), known failure cases (tasks that caused bugs or user complaints), and hand-crafted edge cases (empty inputs, adversarial inputs, boundary conditions). A task bank with all three categories catches a much wider range of regressions than one built from only one source.

Integrating Agent Tests Into CI

Agent tests have different CI requirements than conventional tests. LLM calls are slow and expensive; you can't run your full eval suite on every commit. Structure your CI pipeline in tiers that match speed and cost to the gate.

CI Test Tiers

  • Pre-commit (< 5 seconds): Unit tests only, no LLM calls. Schema validation, prompt rendering, parser tests. Run on every commit push.
  • PR gate (2–5 minutes): Cached eval harness. Use response caching to avoid re-running LLM calls for unchanged prompt sections. Run on every PR.
  • Nightly (10–30 minutes): Full eval harness without caching. Integration tests with real tools. Run every night on main branch.
  • Release gate (1–4 hours): Full integration test suite + E2E tests + adversarial scenarios. Run before every production release.

Common Testing Pitfalls

Pitfall 1, Over-Mocking

When every component is mocked, you're testing the mocks, not the agent. If your LLM is mocked, your tool is mocked, and your database is mocked, a passing test proves nothing about whether your agent actually works. Preserve at least one integration test layer where real components run together.

Pitfall 2, Testing Only the Happy Path

Most agent test suites test the happy path: the task is clear, tools succeed on the first call, the model produces a well-formed response. Production failures cluster in edge cases: ambiguous tasks, tool errors, partial results, context overflow, malformed user input. Explicitly include these in your task bank.

Pitfall 3, Not Versioning Golden Outputs

If your golden outputs aren't in version control, you'll find yourself manually updating them whenever you change a prompt and losing track of whether the change was intentional. Treat golden outputs as code, version them, review changes in PRs, and require explicit sign-off when they change significantly.

Pitfall 4, Ignoring Flakiness

A test that passes 80% of the time is not a test, it's noise. Flaky agent tests are usually caused by over-tight similarity thresholds, tests that depend on live internet state, or tests with no retry logic. Fix flaky tests immediately; don't let them accumulate and erode confidence in the entire test suite.

Frequently Asked Questions

Build secure agentic systems with AgentixForce

We help companies design, build, and secure production-grade AI agent systems. From architecture reviews to full implementation, our team brings deep expertise to every engagement.

More from Testing & Evaluation

All articles
TASK SET100 tasksAGENTrun allEVALjudge modelSCOREmetricsBENCHMARK RESULTSAgentBench74%GAIA Level 188%Custom Eval91%E2E EVALUATION PIPELINE
Testing & Evaluation

End-to-End Evaluation Frameworks for AI Agents: AgentBench, GAIA, and Beyond

What the leading agent benchmarks actually measure, their blind spots, and how to design custom eval suites that reflect what your agent is expected to do in production.

13 min read
May 10, 2026
RED TEAMprompt injectionjailbreak attemptsdata exfiltrationadversarial inputsrole confusionAGENTGUARDFINDINGS✓ blocked: 47✗ bypassed: 3⚠ partial: 8severity:HIGH ██ 2MED ████ 6LOW █ 3RED TEAM SECURITY EXERCISE
Testing & Evaluation

Red-Teaming AI Agents Before Production: A Systematic Approach

Adversarial testing for agents is not optional. How to structure red-team exercises that surface real vulnerabilities before they become incidents in production.

12 min read
May 8, 2026
PROMPT CHANGE REGRESSION TESTPROMPT v1.3tone.formalno_hallucinatetool.routingrefusal.edgelang.consistent5 / 5 passPROMPT v1.4 tone.formal no_hallucinate tool.routing refusal.edge lang.consistent3 / 5 pass ← REGRESSEDREGRESSION TESTING COMPARISON
Testing & Evaluation

Regression Testing for Prompt Changes: Catching Silent Breakages

Changing one line of your system prompt can break a behavior that was working fine for months. How to build regression test suites that catch semantic regressions before they reach users.

9 min read
May 6, 2026
TASKDEFINEAGENTRUNJUDGELLMSCORE&LOGITERATECustom scoring rubric:task_success = agent achieved stated goal? weight: 40%tool_efficiency = minimal unnecessary tool calls? weight: 30%answer_quality = judge model score 1-10 weight: 30%CUSTOM EVALUATION PIPELINE
Testing & Evaluation

Building Custom Evaluation Pipelines for Your Specific Agent

Generic benchmarks will not tell you if your customer support agent is getting better. How to define task-specific metrics and automate evaluation at scale.

10 min read
May 4, 2026
Unit Testing Tool Calls and Agent Logic Without Mocking Everything