Claude Code SDK - Mocking System
View SourceThe Claude Code SDK includes a comprehensive mocking system for testing without making actual API calls.
Overview
The mocking system allows you to:
- Run tests without Claude CLI authentication
- Test your code without incurring API costs
- Create predictable test scenarios
- Speed up test execution
How It Works
- Mock Server: A GenServer that stores mock responses
- Mock Process: Intercepts CLI calls and returns mock data
- Configuration: Simple environment-based switching
Basic Usage
Enable Mocking
# Enable mocking
Application.put_env(:claude_code_sdk, :use_mock, true)
# Start the mock server
{:ok, _} = ClaudeCodeSDK.Mock.start_link()
Set Mock Responses
# Set a response for prompts containing "hello"
ClaudeCodeSDK.Mock.set_response("hello", [
%{
"type" => "assistant",
"message" => %{"content" => "Hello from mock!"},
"session_id" => "mock-123"
}
])
# Now any query containing "hello" will return this response
ClaudeCodeSDK.query("say hello") |> Enum.to_list()
Default Responses
The mock provides default responses for unmatched prompts:
# This will get a default response
ClaudeCodeSDK.query("unmatched prompt") |> Enum.to_list()
Custom Default Response
ClaudeCodeSDK.Mock.set_default_response([
%{
"type" => "assistant",
"message" => %{"content" => "Custom default response"}
}
])
Testing
Running Tests with Mocks (Default)
# Tests use mocks by default
mix test
Running Tests with Live API
# Run tests against real Claude API
MIX_ENV=test mix test.live
# Run specific test file with live API
MIX_ENV=test mix test.live test/specific_test.exs
Environment Configuration
Test Environment (config/test.exs)
config :claude_code_sdk,
use_mock: true # Mocks enabled by default in tests
Development Environment (config/dev.exs)
config :claude_code_sdk,
use_mock: false # Real API calls in development
Runtime Toggle
# Enable mocking at runtime
Application.put_env(:claude_code_sdk, :use_mock, true)
# Disable mocking at runtime
Application.put_env(:claude_code_sdk, :use_mock, false)
Mock Response Format
Mock responses should match the Claude CLI JSON format:
[
# System initialization message
%{
"type" => "system",
"subtype" => "init",
"session_id" => "mock-session-123",
"model" => "claude-3-opus-20240229",
"tools" => ["bash", "editor"],
"cwd" => "/current/dir",
"permissionMode" => "default",
"apiKeySource" => "mock"
},
# Assistant response
%{
"type" => "assistant",
"message" => %{
"role" => "assistant",
"content" => "Your response here"
},
"session_id" => "mock-session-123"
},
# Result message
%{
"type" => "result",
"subtype" => "success",
"session_id" => "mock-session-123",
"total_cost_usd" => 0.001,
"duration_ms" => 100,
"num_turns" => 1,
"is_error" => false
}
]
Example Test
defmodule MyAppTest do
use ExUnit.Case
alias ClaudeCodeSDK.Mock
setup do
Mock.clear_responses()
:ok
end
test "code analysis returns expected format" do
# Set up mock response
Mock.set_response("analyze", [
%{
"type" => "assistant",
"message" => %{
"content" => "Code analysis: No issues found."
}
}
])
# Your code that uses ClaudeCodeSDK
result = MyApp.analyze_code("def hello, do: :world")
# Assertions
assert result == "Code analysis: No issues found."
end
end
Demo Script
Run the included demo to see mocking in action:
mix run demo_mock.exs
Benefits
- Fast Tests: No network calls, instant responses
- Predictable: Same response every time
- No Costs: Zero API usage during testing
- CI/CD Friendly: No authentication needed
- Offline Development: Work without internet
Best Practices
- Clear Mocks: Always clear mocks in test setup
- Specific Patterns: Use specific patterns for mock responses
- Test Both: Test with mocks AND occasionally with live API
- Document Mocks: Document what each mock represents
- Match Reality: Keep mock responses similar to real API
Troubleshooting
Mock Not Working
# Verify mock is enabled
Application.get_env(:claude_code_sdk, :use_mock)
# Should return true
# Verify mock server is running
Process.whereis(ClaudeCodeSDK.Mock)
# Should return a PID
Wrong Response
# Check registered patterns
# The mock uses String.contains? for matching
Mock.set_response("specific phrase", [...])
Mix Task Issues
# Ensure test environment for mix test.live
MIX_ENV=test mix test.live