# Testing Guide
ExLLM includes a comprehensive testing system with intelligent caching, semantic tagging, and 24 specialized Mix aliases for targeted test execution.
## Quick Start
```bash
# Run all tests (fast - uses cache when available)
mix test
# Run provider-specific tests
mix test.anthropic
mix test.openai
mix test.gemini
# Run integration tests with live APIs
mix test.integration --include live_api
# Run tests by capability
mix test.streaming
mix test.vision
mix test.oauth2
# Manage test cache
mix ex_llm.cache stats
mix ex_llm.cache clean --older-than 7d
```
## Test Organization
### Test Tags
ExLLM uses semantic tags to organize tests by requirements, capabilities, and providers:
#### **Requirement Tags**
- `:requires_api_key` - Tests needing API keys with automatic provider detection
- `:requires_oauth` - Tests needing OAuth2 authentication (e.g., Gemini APIs)
- `:requires_service` - Tests needing local services (Ollama, LM Studio)
- `:requires_resource` - Tests needing pre-existing resources (tuned models, corpora)
#### **Test Type Tags**
- `:live_api` - Tests that call live provider APIs
- `:integration` - Integration tests with external services
- `:external` - Tests making external network calls
- `:unit` - Unit tests (isolated, no external dependencies)
#### **Provider Tags**
- `:anthropic`, `:openai`, `:gemini`, `:groq`, `:mistral`
- `:openrouter`, `:perplexity`, `:ollama`, `:lmstudio`, `:bumblebee`
#### **Capability Tags**
- `:streaming` - Tests for streaming responses
- `:vision` - Tests for image/vision capabilities
- `:multimodal` - Tests for multimodal inputs
- `:function_calling` - Tests for tool/function calling
- `:embedding` - Tests for embedding generation
## Mix Test Aliases
ExLLM provides 24 specialized test aliases for targeted execution:
### Provider-Specific Tests
```bash
# Test individual providers
mix test.anthropic # Anthropic Claude tests
mix test.openai # OpenAI GPT tests
mix test.gemini # Google Gemini tests
mix test.groq # Groq tests
mix test.mistral # Mistral AI tests
mix test.openrouter # OpenRouter tests
mix test.perplexity # Perplexity tests
mix test.ollama # Ollama local tests
mix test.lmstudio # LM Studio tests
mix test.bumblebee # Bumblebee local tests
```
### Test Type Aliases
```bash
# By test type
mix test.unit # Unit tests only
mix test.integration # Integration tests
mix test.external # Tests with external calls
mix test.oauth2 # OAuth2 authentication tests
```
### Capability-Based Tests
```bash
# By capability
mix test.streaming # Streaming response tests
mix test.vision # Vision/image processing tests
mix test.multimodal # Multimodal input tests
mix test.function_calling # Function/tool calling tests
mix test.embedding # Embedding generation tests
```
### Environment-Based Tests
```bash
# By environment needs
mix test.live_api # Tests calling live APIs
mix test.local_only # Local-only tests (no API calls)
mix test.fast # Fast tests (cached/mocked)
mix test.all # All tests including slow ones
```
## Test Caching System
ExLLM includes an advanced caching system that provides 25x speed improvements for integration tests.
### How It Works
1. **Automatic Detection**: Tests tagged with `:live_api` are automatically cached
2. **Smart Exclusions**: Destructive operations (create, delete, modify) are not cached
3. **TTL Management**: Cached responses expire after 7 days by default
4. **Fallback Strategies**: Multiple matching algorithms for cache hits
### Cache Management
```bash
# View cache statistics
mix ex_llm.cache stats
# Clean old cache entries
mix ex_llm.cache clean --older-than 7d
# Clear all cache
mix ex_llm.cache clear
# Show cache details for a provider
mix ex_llm.cache show anthropic
```
### Configuration
Configure caching via environment variables:
```bash
# Enable/disable caching
export EX_LLM_TEST_CACHE_ENABLED=true
# Cache directory
export EX_LLM_TEST_CACHE_DIR="test/cache"
# TTL for cached responses (in seconds)
export EX_LLM_TEST_CACHE_TTL=604800 # 7 days
# Cache destructive operations
export EX_LLM_TEST_CACHE_DESTRUCTIVE_OPS=false
```
## Writing Tests
### Basic Test Structure
```elixir
defmodule MyProviderTest do
use ExUnit.Case
# Module-level tags
@moduletag :integration
@moduletag :live_api
@moduletag :requires_api_key
@moduletag provider: :anthropic
# Import cache helpers
import ExLLM.TestCacheHelpers
setup_all do
enable_cache_debug()
:ok
end
setup context do
setup_test_cache(context)
on_exit(fn -> ExLLM.TestCacheDetector.clear_test_context() end)
:ok
end
test "basic chat completion" do
{:ok, response} = ExLLM.chat(:anthropic, [
%{role: "user", content: "Hello!"}
])
assert response.content != ""
end
end
```
### Using ExLLM.Case for Automatic Requirements
```elixir
defmodule MyProviderTest do
use ExLLM.Case, async: true
@moduletag :requires_api_key
@moduletag provider: :openai
test "test with automatic API key checking", context do
# Automatically skips if OPENAI_API_KEY not set
check_test_requirements!(context)
{:ok, response} = ExLLM.chat(:openai, [
%{role: "user", content: "Test"}
])
assert response.content != ""
end
end
```
### OAuth2 Tests
```elixir
defmodule GeminiOAuth2Test do
use ExLLM.Case, async: true
@moduletag :requires_oauth
@moduletag provider: :gemini
test "OAuth2 API call", context do
check_test_requirements!(context)
# OAuth token automatically provided if available
oauth_token = get_oauth_token(context)
{:ok, response} = ExLLM.Gemini.Permissions.list_permissions(
"tunedModels/test",
oauth_token: oauth_token
)
assert is_list(response.permissions)
end
end
```
## Test Exclusions
### Default Exclusions
By default, these tests are excluded unless explicitly included:
```bash
# In test_helper.exs
ExUnit.configure(exclude: [
:live_api, # Exclude live API calls by default
:requires_api_key, # Exclude tests needing API keys
:requires_oauth, # Exclude OAuth tests
:requires_service, # Exclude tests needing local services
:integration, # Exclude integration tests
:external # Exclude external network tests
])
```
### Running Excluded Tests
```bash
# Include specific tags
mix test --include live_api
mix test --include requires_api_key
mix test --include oauth2
# Include multiple tags
mix test --include live_api --include streaming
# Run only specific tags
mix test --only provider:anthropic
mix test --only streaming
```
## CI/CD Integration
### GitHub Actions Example
```yaml
name: Tests
on: [push, pull_request]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'
# Unit tests only (no API keys needed)
- run: mix test.unit
integration-tests:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v3
- uses: erlef/setup-beam@v1
# Integration tests with caching
- run: mix test.integration --include live_api
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EX_LLM_TEST_CACHE_ENABLED: true
```
## Performance Tips
1. **Use Caching**: Enable test caching for 25x faster integration tests
2. **Tag Appropriately**: Use semantic tags for precise test selection
3. **Run Targeted Tests**: Use Mix aliases to run only what you need
4. **Cache Management**: Regularly clean old cache entries
5. **Local Services**: Use Ollama/LM Studio for development without API costs
## Troubleshooting
### Common Issues
**Tests skipped with "API key required":**
```bash
# Set the required API key
export ANTHROPIC_API_KEY="your-key"
mix test.anthropic
```
**OAuth2 tests failing:**
```bash
# Setup OAuth2 first
elixir scripts/setup_oauth2.exs
# Then refresh token
elixir scripts/refresh_oauth2_token.exs
```
**Cache not working:**
```bash
# Check cache configuration
mix ex_llm.cache stats
# Enable debug logging
export EX_LLM_LOG_LEVEL=debug
```
**Tests timing out:**
```bash
# Use cached responses
export EX_LLM_TEST_CACHE_ENABLED=true
mix test --include live_api
```
### Debug Logging
Enable debug logging to troubleshoot test issues:
```bash
export EX_LLM_LOG_LEVEL=debug
export EX_LLM_LOG_COMPONENTS=http_client,cache,test_detector
mix test --include live_api
```
This comprehensive testing system ensures reliable, fast, and well-organized tests across all ExLLM functionality.