Alkiviades — Testing Guide¶
Test Structure¶
backend/tests/
├── __init__.py # Package marker
├── conftest.py # Shared fixtures
├── test_auth.py # Auth unit tests (JWT, bcrypt, cookies)
├── test_auth_endpoints.py # Auth API integration tests (FastAPI TestClient)
├── test_database.py # Database integration tests
├── test_files.py # File I/O operations
├── test_httpx_streaming.py # httpx streaming compatibility
├── test_prompt.py # Prompt assembly
├── test_rag.py # RAG pipeline (chunking, embedding, retrieval)
├── test_session.py # (future) Session persistence
├── test_stream_events.py # SSE event mapping
├── test_streaming_agent.py # E2E agent streaming
├── test_tools.py # (future) Tool execution
├── test_user_store.py # Agent registry LRU/TTL
└── test_utils.py # Utility functions
Running Tests¶
All Tests¶
Unit Tests Only (no API keys needed)¶
python -m pytest backend/tests/ \
--ignore=backend/tests/test_auth_endpoints.py \
--ignore=backend/tests/test_database.py \
--ignore=backend/tests/test_streaming_agent.py \
--ignore=backend/tests/test_httpx_streaming.py \
--ignore=backend/tests/test_user_store.py \
-v
Single File¶
Single Test¶
With Coverage¶
Test Categories¶
Unit Tests¶
Tests that don't require external services (no API keys, no network):
| File | Tests | What It Tests |
|---|---|---|
test_auth.py |
12 | JWT creation/decoding/expiry, bcrypt hash/verify, cookie helpers |
test_rag.py |
10 | Markdown chunking, TF-IDF fitting/embedding, cosine similarity, manifest diff |
test_prompt.py |
5 | User message assembly, axis interpolation |
test_utils.py |
10 | Token counting, slugify, sanitize, JSON safety |
test_files.py |
7 | Read/write/edit file operations, path traversal prevention |
test_stream_events.py |
4 | SSE event mapping, heartbeat generator |
Integration Tests¶
Tests that use the FastAPI TestClient with a temporary SQLite database:
| File | Tests | What It Tests |
|---|---|---|
test_auth_endpoints.py |
12 | Login, refresh, logout, protected endpoints |
test_database.py |
7 | Schema init, admin bootstrap, WAL mode |
test_user_store.py |
7 | AgentRegistry LRU/TTL eviction, concurrent access |
E2E Tests¶
Tests that call the real DeepSeek API (require DEEPSEEK_API_KEY):
| File | Tests | What It Tests |
|---|---|---|
test_streaming_agent.py |
1 | Full agent streaming flow |
test_httpx_streaming.py |
2 | httpx streaming compatibility |
Markers¶
Use pytest markers to filter tests:
# Run only integration tests
python -m pytest backend/tests/ -m integration -v
# Skip slow tests
python -m pytest backend/tests/ -m "not slow" -v
Available markers (defined in conftest.py):
- integration: Requires API keys or external services
- slow: Takes >1 second
Fixtures¶
Shared fixtures in conftest.py:
| Fixture | Type | Description |
|---|---|---|
temp_dir |
Path | Temporary directory (auto-cleaned) |
mock_embedder |
Embedder | Pre-fitted embedder with sample texts |
sample_chunks |
list[Chunk] | 5 sample chunks for testing |
temp_kb |
KnowledgeBase | KB with temporary vectors file |
test_db |
str | Temporary SQLite database path |
app_with_db |
(TestClient, str) | FastAPI TestClient with test DB |
auth_headers |
dict | Pre-authenticated JWT headers |
Writing New Tests¶
- Use the shared fixtures from
conftest.py - Mock external APIs (DeepSeek, Tavily) with
unittest.mockorpytest-mock - Use FastAPI's
TestClientfor endpoint tests - Tag integration/slow tests with appropriate marks
- Follow existing patterns in matching test files
Example: Unit Test¶
from app.embed import Embedder
def test_embedder_fit_builds_vocab():
embedder = Embedder(dtype="float32")
embedder.fit(["hello world", "hello python"])
assert "hello" in embedder.vocab
assert len(embedder.vocab) >= 3 # hello, world, python
Example: API Test¶
def test_health(client):
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
CI/CD¶
For GitHub Actions or similar, add a test workflow:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r backend/requirements.txt pytest
- run: python -m pytest backend/tests/ -v \
--ignore=backend/tests/test_auth_endpoints.py \
--ignore=backend/tests/test_streaming_agent.py \
--ignore=backend/tests/test_httpx_streaming.py