src/voicegateway/tests/, mirroring the package layout (tests/middleware/ for middleware/, tests/core/ for core/, and so on). The coverage gate is fail_under under [tool.coverage.report] in pyproject.toml.
Running tests
pytest configuration
pyproject.toml sets:
asyncio_mode = "auto" means async def test_... functions run without a @pytest.mark.asyncio decorator.
Shared fixtures
src/voicegateway/tests/conftest.py defines:
_test_env (autouse)
Sets fake API keys (OPENAI_API_KEY, DEEPGRAM_API_KEY, CARTESIA_API_KEY, ANTHROPIC_API_KEY, GROQ_API_KEY, ELEVENLABS_API_KEY, ASSEMBLYAI_API_KEY) via monkeypatch so provider constructors never fail on a missing key. Runs for every test automatically.
_isolate_db_path_env (autouse)
Snapshots and restores VOICEGW_DB_PATH around each test. VOICEGW_DB_PATH beats every other DB path source, so a test that sets it and forgets to unset it redirects every later StorageService in the run into one shared file. If you see no such table on a test’s own tmp database, or a UNIQUE-constraint collision between unrelated tests, this is usually the cause: check for a leaked monkeypatch.setenv("VOICEGW_DB_PATH", ...) outside this fixture’s protection.
example_config_path
Writes the bundled starter config (src/voicegateway/data/voicegw.example.yaml) to a tmp file and returns its path:
temp_config
Writes a minimal voicegw.yaml (OpenAI + Deepgram providers, one STT model, one LLM model, a test-project and blocked-project, cost tracking on) to a tmp directory, points VOICEGW_DB_PATH at an isolated file, and returns the config path:
seeded_storage
Async fixture. Creates a StorageService (src/voicegateway/services/storage_service.py) pre-loaded with three sample RequestRecord rows:
Writing tests
File-name pattern:test_<module>.py. Function-name pattern: test_<behaviour>.
Async tests
Write plainasync def test_... functions; asyncio_mode = "auto" picks them up without a decorator. The next section has a full example.
Mocking a provider’s health check
BaseProvider.health_check() is the only method a provider subclass exercises in production (the health-check surface: dashboard Test Connection, voicegw doctor, the MCP server’s admin test_provider tool). Follow src/voicegateway/tests/providers/test_cartesia_health_check.py: mock httpx.AsyncClient, not the provider method itself.
Resolving a provider/model string
Testing cost calculations
voicegateway.inference.pricing.catalog.calculate_cost(modality, model, **units) is the modality-dispatching entry point; stt.py / llm.py / tts.py do the actual voice-prices lookup per modality. See Refreshing Pricing.
Testing storage directly
monkeypatch.setenv for environment variables
Coverage expectations
- New features must include tests.
- Bug fixes should include a regression test.
- The suite must stay at or above
fail_underinpyproject.toml’s[tool.coverage.report].