Testing
VoiceGateway has 200+ tests with over 70% code coverage. This guide covers running tests, writing new ones, and using the shared fixtures.Running tests
pytest configuration
VoiceGateway usesasyncio_mode = "auto" in pyproject.toml:
- No
@pytest.mark.asyncioneeded — async test functions are detected automatically - All tests run in the same event loop policy — no loop conflicts
- Test files live in the
src/voicegateway/tests/directory
Shared fixtures
Thesrc/voicegateway/tests/conftest.py file provides four key fixtures:
_test_env (autouse)
Runs automatically for every test. Sets fake API keys so provider constructors do not fail:
example_config_path
Writes the bundled starter config (sourced from src/voicegateway/data/voicegw.example.yaml) to a tmp file and returns its path. Use this to test config loading against the shipped example:
temp_config
Writes a minimal voicegw.yaml to a temporary directory and returns its path. The config includes OpenAI and Deepgram providers, one STT model, one LLM model, two projects (test-project and blocked-project), and cost tracking enabled:
seeded_storage
Creates a SQLiteStorage instance pre-loaded with three sample RequestRecord entries:
| Record | Modality | Model | Project | Cost |
|---|---|---|---|---|
| 1 | stt | deepgram/nova-3 | test-project | $0.0043 |
| 2 | llm | openai/gpt-4o-mini | test-project | $0.015 |
| 3 | llm | openai/gpt-4o-mini | default | $0.008 |
Writing tests
Test file naming
- Test files:
src/voicegateway/tests/test_<module>.py - Test functions:
test_<what_it_tests> - Test classes (grouping related tests):
TestClassName
Async tests
Write async tests as regularasync def functions. The asyncio_mode = "auto" setting handles the rest:
Mocking providers
Providers make HTTP calls to external APIs. Always mock these in tests:Mocking the config
Usetemp_config for tests that need a Gateway instance, or construct configs directly:
Testing cost calculations
Testing middleware
Middleware wraps provider calls. Test the wrapping behavior:Mock patterns
monkeypatch.setenv for environment variables
tmp_path for temporary files
pytest’s built-in tmp_path fixture provides a temporary directory unique to each test:
patch for external HTTP calls
Coverage expectations
- New features must include tests
- Bug fixes should include a regression test
- Target: maintain above 70% overall coverage
- Critical paths (Gateway, Router, CostTracker, BudgetEnforcer) should be above 90%