Framework
- pytest + pytest-asyncio (
asyncio_mode = "auto"— no@pytest.mark.asyncioneeded) - Test root:
backend/tests/ - Shared fixtures:
backend/tests/conftest.py
File Naming
One test file per module: test_{module_name}.py
test_agents.py # Agent output validation
test_config.py # BrainConfig field validation
test_ingest.py # VaultIngester classify/parse/ingest
test_mcp_server.py # MCP tool input validation + routing
test_schemas.py # Pydantic schema instantiation
test_services.py # Service layer unit tests
test_parsers.py # Parser functions
Test Patterns
# Unit test — mock services, test logic in isolation
async def test_classify_file_client_transcript(tmp_path):
config = BrainConfig(...)
ingester = VaultIngester(config)
filepath = tmp_path / "clients" / "acme" / "transcripts" / "call.md"
meta = ingester.classify_file(filepath)
assert meta.category == "transcript"
assert meta.client == "acme"
# Config validation test
def test_config_rejects_invalid_transport():
with pytest.raises(ValidationError):
BrainConfig(mcp_transport="invalid", ...)Running Tests
# All tests
pytest backend/tests/
# Verbose with output
pytest backend/tests/ -v -s
# Single file
pytest backend/tests/test_ingest.py
# Single test
pytest backend/tests/test_config.py::test_validate_graph_configWhat to Test
- Config: field defaults, validators, env var loading
- Schemas: model instantiation with required fields
- Services: core logic with mocked external clients
- Agents: output_validator logic, tool error handling
- MCP tools: input validation (
_validate_mcp_input), timeout handling