Testing Guide¶
This guide covers testing practices, patterns, and tools used in Routstr Core development.
Testing Philosophy¶
We follow these principles:
- Test behavior, not implementation
- Fast feedback
- Reliable tests
- Clear failures
Test Structure¶
tests/
├── integration/
│ ├── conftest.py
│ ├── utils.py
│ ├── test_wallet_topup.py
│ ├── test_wallet_refund.py
│ ├── test_wallet_information.py
│ ├── test_proxy_get_endpoints.py
│ ├── test_proxy_post_endpoints.py
│ └── ... more integration tests
├── unit/
│ ├── test_algorithm.py
│ ├── test_fee_consistency.py
│ ├── test_image_tokens.py
│ ├── test_logging_securityfilter.py
│ ├── test_payment_helpers.py
│ ├── test_settings.py
│ ├── test_wallet.py
│ └── ... more unit tests
└── run_integration.py
Running Tests¶
Make Targets¶
# Run all tests (unit + integration with mocks)
make test
# Unit tests only
make test-unit
# Integration tests with mocks (fast)
make test-integration
# Integration tests with Docker services
make test-integration-docker
# Fast tests only (skip slow and Docker tests)
make test-fast
# Performance tests
make test-performance
# Coverage
make test-coverage
Direct pytest Commands¶
# Run all tests
pytest
# Run a specific test file
pytest tests/unit/test_wallet.py -v
# Run a specific test
pytest tests/unit/test_wallet.py::test_get_balance -v
# Run tests matching a pattern
pytest -k "wallet" -v
Test Modes (Integration)¶
Integration tests support two execution modes:
- Mock mode (default): uses in-memory mocks, no Docker required
- Docker mode: uses real Docker services (Cashu mint, mock OpenAI, Nostr relay)
Use the runner script for Docker mode:
./tests/run_integration.py
Or manually:
docker-compose -f compose.testing.yml up -d
USE_LOCAL_SERVICES=1 pytest tests/integration/ -v
docker-compose -f compose.testing.yml down -v
Test Markers¶
Markers are defined in pyproject.toml:
integrationunitslowrequires_dockerrequires_real_mintperformanceasyncio
Examples:
# Skip slow tests
pytest -m "not slow" -v
# Run only integration tests
pytest -m "integration" -v
# Run performance tests
pytest -m "performance" -v
Fixtures and Utilities¶
Core Integration Fixtures¶
Defined in tests/integration/conftest.py:
integration_client- Async HTTP client for the FastAPI appauthenticated_client- Client with a pre-created API keytestmint_wallet- Test wallet for generating Cashu tokensdb_snapshot- Database state snapshot/diff helpercreate_api_key- Helper to create API keys for testsintegration_engine,integration_session- Async DB engine/sessionbackground_tasks_controller- Control background tasks in testsmock_upstream_server- Mock upstream API responses
Integration Utilities¶
Defined in tests/integration/utils.py:
CashuTokenGeneratorResponseValidatorPerformanceValidatorConcurrencyTesterDatabaseStateValidatorMockServiceBuilderTestDataBuilder
Writing Tests¶
Unit Test Example¶
from routstr.algorithm import calculate_model_cost_score
from routstr.payment.models import Architecture, Model, Pricing
def test_calculate_model_cost_score_basic() -> None:
model = Model(
id="test-model",
name="Test test-model",
created=1234567890,
description="Test model",
context_length=8192,
architecture=Architecture(
modality="text",
input_modalities=["text"],
output_modalities=["text"],
tokenizer="gpt",
instruct_type=None,
),
pricing=Pricing(
prompt=0.001,
completion=0.002,
request=0.0,
image=0.0,
web_search=0.0,
internal_reasoning=0.0,
),
)
assert calculate_model_cost_score(model) == 0.002
Integration Test Example¶
import pytest
from httpx import AsyncClient
@pytest.mark.integration
@pytest.mark.asyncio
async def test_wallet_topup(
authenticated_client: AsyncClient,
testmint_wallet: object,
db_snapshot: object,
) -> None:
await db_snapshot.capture()
token = await testmint_wallet.mint_tokens(1000)
response = await authenticated_client.post(
"/v1/wallet/topup", params={"cashu_token": token}
)
assert response.status_code == 200
diff = await db_snapshot.diff()
assert len(diff["api_keys"]["modified"]) == 1
Debugging Tips¶
# Show print output
pytest -s tests/unit/test_wallet.py
# Drop into debugger on failure
pytest --pdb
Troubleshooting¶
- Docker mode failures: check
docker psanddocker-compose -f compose.testing.yml logs - Connection errors: make sure ports 3338, 3000, 8000, and 8088 are free
- Slow tests: use
pytest -m "not slow"ormake test-fast
Next Steps¶
- See Architecture
- Read Setup Guide