Tests live in the tests/ directory and are run with pytest.
tests/
├── conftest.py # Shared fixtures (DB clients, mock clients, etc.)
├── fixtures.py # Additional fixtures
├── test_database.py # Database integration tests
├── test_pydantic_to_marshmallow.py # Schema conversion tests
├── test_schema_validation.py # Schema validation tests
├── test_schema_aligned_with_db_table.py # Schema-DB alignment tests
├── db_client/ # DatabaseClient unit tests
├── integration/ # Integration tests
│ └── notifications/ # Notification event flow tests
├── middleware/ # Middleware logic tests
├── helpers/ # Test helper functions
├── utilities/ # Utility tests
├── _mocks/ # Mock data and fixtures
└── alembic/ # Migration tests
You need a database connection. Either:
- A running local Docker database (see Database Setup), or
- A sandbox database connection string.
Set DO_DATABASE_URL in your .env file.
uv run pytest tests# Run a single file
uv run pytest tests/test_database.py
# Run a specific test function
uv run pytest tests/test_database.py::test_function_name
# Run tests in a directory
uv run pytest tests/middleware/
# Run with verbose output
uv run pytest tests -vTests run automatically on every pull request via the run_pytest.yml GitHub Action:
- A fresh PostgreSQL 15 container is started.
- Dependencies are installed with
uv sync --locked --all-extras --dev. - Alembic migrations are run against the fresh database.
uv run pytest testsruns all tests.- Tests have a 20-minute timeout.
The CI environment uses dummy values for auth secrets (JWT keys, GitHub OAuth) — these are sufficient for tests that don't make real external calls.
- Place tests in the appropriate subdirectory matching the code being tested.
- Use fixtures from
conftest.pyfor database clients and mock setup. - Test output schemas to validate response format.
- Use Pydantic DTOs to validate response structure where applicable.
The test suite provides fixtures for database access and mock setup. Check tests/conftest.py and tests/fixtures.py for the current list.
Query builders can be tested by running them against the test database:
def test_my_query(dev_db_client):
result = dev_db_client.run_query_builder(MyQuery(...))
assert result is not NoneEndpoint tests typically use Flask's test client or FastAPI's TestClient to make requests and validate responses against expected schemas.
Manual tests for third-party integrations (GitHub, email/Mailgun) live in manual_tests/. These require real credentials and are not run in CI.
See manual_tests/README.md for instructions.
Two remote test databases are available:
| Database | Purpose | Sensitive Data? |
|---|---|---|
| Sandbox | Developer testing, schema experiments | No |
| Stage | Pre-release integration testing | Yes |
Both are refreshed daily from production. Connection details are available through DigitalOcean (admin access required) or environment variables on the Jenkins migration job. Reach out to the team in Discord for access.