An in-memory Guava.Call for unit-testing agent callbacks without a server.
Guava.Testing.session/3 drives a whole agent against the live test endpoint;
MockCall is the complement for fast, offline, deterministic tests: call a
single handler directly and assert on the commands it emits — no network, no
LLM, no supervision.
A mock records every command your handler emits, in order, and holds an
ETS-backed store for field and variable reads, so Guava.Call actions and
reads behave exactly as they do on a live call.
test "assigns the intake task on call start" do
mock = Guava.Testing.MockCall.new()
{:noreply, _state} =
MyAgent.handle_call_started(mock.call, MyAgent.initial_state())
assert [%Guava.Commands.SetTask{task_id: "intake"}] =
Guava.Testing.MockCall.commands(mock)
endPre-seed collected fields and variables that a handler reads back:
mock = Guava.Testing.MockCall.new(fields: %{"email" => "a@b.com"})
Guava.Testing.MockCall.put_variable(mock, "tier", "gold")Assert on the exact wire shape with command_maps/1:
Guava.Call.send_dtmf(mock.call, "123")
assert [%{"command_type" => "send-agent-dtmf", "digits" => ["1", "2", "3"]}] =
Guava.Testing.MockCall.command_maps(mock)Scope
A mock exercises a handler in isolation. It does not run the call runtime, so
runtime orchestration — for example, field validators firing automatically when
a task completes — is out of scope; cover that with a live session/3. You can
still unit-test a validator directly by calling Guava.Agent.handle_validate/4
yourself.
Command capture is per-process
Commands are captured from the process that calls the handler. If a handler
offloads work to a spawned Task, emits from that task are not visible to
commands/1 unless you await it first.
Summary
Functions
The Guava.Call handle to pass to your handlers. Equivalent to mock.call.
Returns a specification to start this module under a supervisor.
Discard all recorded commands (e.g. between simulated turns).
Every command emitted so far as wire maps (via Guava.Commands.to_map/1), in
order — for asserting on the exact serialized shape.
Every command emitted so far, as structs, in the order emitted.
Build a mock call.
Pre-seed a call variable, readable via Guava.Call.get_variable/3.
Pre-seed a collected field value, readable via Guava.Call.get_field/3.
Stop the recorder process. Optional — it is linked to the test process and stops with it.
Types
@type t() :: %Guava.Testing.MockCall{ call: Guava.Call.t(), pid: pid(), table: :ets.tid() }
Functions
@spec call(t()) :: Guava.Call.t()
The Guava.Call handle to pass to your handlers. Equivalent to mock.call.
Returns a specification to start this module under a supervisor.
See Supervisor.
Discard all recorded commands (e.g. between simulated turns).
Every command emitted so far as wire maps (via Guava.Commands.to_map/1), in
order — for asserting on the exact serialized shape.
Every command emitted so far, as structs, in the order emitted.
Build a mock call.
The recorder process is linked to the calling (test) process, so it — and its ETS store — are cleaned up automatically when the test ends.
Options
:id— the call/session id (default: a generated"mock-…"id).:call_info— aGuava.CallInfo(default: a PSTN call). Pass aGuava.CallInfo.WebRTC{}to exercise WebRTC-only guards.:fields— map offield_key => valueto pre-seed as collected fields.:variables— map ofkey => valueto pre-seed as call variables.
Pre-seed a call variable, readable via Guava.Call.get_variable/3.
Emits no command, unlike Guava.Call.set_variable/3.
Pre-seed a collected field value, readable via Guava.Call.get_field/3.
Emits no command (unlike a field being collected during a live call).
@spec stop(t()) :: :ok
Stop the recorder process. Optional — it is linked to the test process and stops with it.