Local Development & Testing Setup
Guide to setting up local development and testing with Docker and in-memory alternatives for Redis
Local Development & Testing Setup
This guide covers setting up local development and running tests.
Overview
| Component | Production | Local Dev | Test |
|---|---|---|---|
| Database | PostgreSQL (Neon) | Docker PostgreSQL | Docker PostgreSQL or TEST_DATABASE_URL |
| Cache | Redis | Docker Redis | LocMemCache |
| Channels | Redis | Docker Redis | InMemoryChannelLayer |
| Celery | Redis broker | Eager mode (sync) | Eager mode |
| Resend | SMTP (Mailpit) | LocMem backend |
Local Development with Docker
Use compose.lean.yaml to run PostgreSQL, Redis, and Mailpit:
docker compose -f compose.lean.yaml up -dThis starts:
- PostgreSQL on port 5432
- Redis on port 6379
- Mailpit on port 1025 (SMTP) and 8025 (web UI)
Redis Alternatives for Tests
Cache
Already configured to use LocMemCache for tests:
if TEST_ENV:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "",
}
}Django Channels
Use the built-in InMemoryChannelLayer:
if TEST_ENV:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer",
},
}Note: InMemoryChannelLayer is single-process only. For multi-process testing, use fakeredis.
Celery
Already configured for eager/synchronous execution in local/test:
if DJANGO_ENV == "local":
CELERY_TASK_ALWAYS_EAGER = True
CELERY_TASK_EAGER_PROPAGATES = TrueTasks execute synchronously without Redis.
fakeredis (Optional)
For code that directly uses Redis (not via Django cache/channels):
uv add --dev "fakeredis[lua]"import fakeredis
# Create fake Redis connection
fake_redis = fakeredis.FakeRedis()
# Use like regular Redis
fake_redis.set("key", "value")
fake_redis.get("key") # b'value'
# Pubsub supported
pubsub = fake_redis.pubsub()
pubsub.subscribe("channel")
fake_redis.publish("channel", "message")fakeredis Limitations
- No persistence - Data lost when process ends (same as Redis pubsub)
- Single process - Doesn't work across multiple processes
- Lua scripts - Requires
fakeredis[lua]extra
Running Tests
# Set environment
export DJANGO_ENV=test
# Run all tests
cd backend && uv run pytest tests/ -v
# Run specific app tests
uv run pytest tests/dashboard/ -v
# With coverage
uv run pytest tests/ --cov=apps --cov-report=htmlCI Configuration
Example GitHub Actions workflow with PostgreSQL service:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Install dependencies
run: |
cd backend
uv sync --frozen
- name: Run tests
env:
DJANGO_ENV: test
DJANGO_SECRET_KEY: test-secret-key
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
run: |
cd backend
uv run pytest tests/ -vTroubleshooting
Channel layer issues in tests
For WebSocket tests, ensure you're using InMemoryChannelLayer:
@pytest.fixture
def channel_layer():
from channels.layers import get_channel_layer
return get_channel_layer()Database connection issues
Ensure Docker is running and the database container is healthy:
docker compose -f compose.lean.yaml psSlow test startup
If tests are slow:
- Use
--reuse-dbpytest flag (already configured) - Consider running tests in parallel with
pytest-xdist
Last updated on