Mock Provider
The Mock provider is a mock provider for testing agents without making real API calls.
Usage
No additional gems required. Use the mock provider identifier:
class TestableAgent < Riffer::Agent model 'mock/any' # The model name doesn't matter for mock provider instructions 'You are helpful.' uses_tools [MyTool] end
Stubbing Responses
Use stub_response to queue responses:
# Get the provider instance from the agent agent = TestableAgent.new provider = agent.send(:provider_instance) # Stub a simple text response provider.stub_response("Hello, I'm here to help!") # Now generate will return the stubbed response response = agent.generate("Hi") # => "Hello, I'm here to help!"
Stubbing Tool Calls
Stub responses that trigger tool execution:
provider.stub_response("", tool_calls: [ {name: "my_tool", arguments: '{"query":"test"}'} ]) # Queue the response after tool execution provider.stub_response("Based on the tool result, here's my answer.") response = agent.generate("Use the tool")
Queueing Multiple Responses
Responses are consumed in order:
provider.stub_response("First response") provider.stub_response("Second response") provider.stub_response("Third response") agent.generate("Message 1") # => "First response" agent.generate("Message 2") # => "Second response" agent.generate("Message 3") # => "Third response" agent.generate("Message 4") # => "Mock response" (default)
Inspecting Calls
Access recorded calls for assertions:
provider.calls # => [ # {messages: [...], model: "any", tools: [...], ...}, # {messages: [...], model: "any", tools: [...], ...} # ] # Check what was sent expect(provider.calls.last[:messages].last[:content]).to eq("Hi")
Clearing State
Reset stubbed responses:
provider.clear_stubs
Example Test
require 'minitest/autorun' class MyAgentTest < Minitest::Test def setup @agent = TestableAgent.new @provider = @agent.send(:provider_instance) end def test_generates_response @provider.stub_response("Hello!") response = @agent.generate("Hi") assert_equal "Hello!", response end def test_executes_tool @provider.stub_response("", tool_calls: [ {name: "weather_tool", arguments: '{"city":"Tokyo"}'} ]) @provider.stub_response("The weather is sunny.") response = @agent.generate("What's the weather?") assert_equal "The weather is sunny.", response assert_equal 2, @provider.calls.length end def test_passes_context_to_tools @provider.stub_response("", tool_calls: [ {name: "user_tool", arguments: '{}'} ]) @provider.stub_response("Done.") @agent.generate("Do something", tool_context: {user_id: 123}) # Tool receives the context end end
Streaming
The mock provider also supports streaming:
provider.stub_response("Hello world.") events = [] agent.stream("Hi").each { |e| events << e } # Events include TextDelta and TextDone text_deltas = events.select { |e| e.is_a?(Riffer::StreamEvents::TextDelta) } text_done = events.find { |e| e.is_a?(Riffer::StreamEvents::TextDone) }
Web Search
The test provider emits web search events when web_search: true is passed to the stream call:
provider.stub_response("Here are the latest results.") events = [] agent.stream("What's new in Ruby?", web_search: true).each { |e| events << e } # Events include WebSearchStatus and WebSearchDone before text events search_deltas = events.select { |e| e.is_a?(Riffer::StreamEvents::WebSearchStatus) } search_done = events.find { |e| e.is_a?(Riffer::StreamEvents::WebSearchDone) } search_done.query # => "test search query" search_done.sources # => [{title: "Example", url: "https://example.com"}]
Initial Responses
Pass responses during initialization:
provider = Riffer::Providers::Mock.new(responses: [ {content: "First"}, {content: "Second"} ])
Default Response
When no stubs are queued and initial responses are exhausted, the provider returns:
{role: "assistant", content: "Mock response"}