Flask Testing & Deployment

πŸ§ͺ Test client setup

import pytest
from app import create_app
 
@pytest.fixture
def client():
    app = create_app(TestingConfig)
    with app.test_client() as client:
        yield client
class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
    WTF_CSRF_ENABLED = False   # skip CSRF friction in tests

βœ… Writing tests

def test_home_page(client):
    response = client.get("/")
    assert response.status_code == 200
    assert b"Welcome" in response.data      # response.data is bytes, use b"..."
 
def test_create_user(client):
    response = client.post("/api/users", json={"username": "amit"})   # json= auto-sets Content-Type
    assert response.status_code == 201
    assert response.get_json()["username"] == "amit"
 
def test_dashboard_requires_login(client):
    assert client.get("/dashboard").status_code == 401
 
def test_dashboard_with_login(client):
    client.post("/login", data={"username": "amit", "password": "secret"})
    assert client.get("/dashboard").status_code == 200   # cookies persist across requests on same client

πŸ—„οΈ Fresh DB per test

@pytest.fixture
def app():
    app = create_app(TestingConfig)
    with app.app_context():
        db.create_all()
        yield app
        db.session.remove()
        db.drop_all()
 
@pytest.fixture
def client(app):
    return app.test_client()

πŸƒ Running tests

pip install pytest
pytest              # all tests
pytest -v              # verbose
pytest tests/test_api.py   # one file
pytest -k "test_login"        # match by name

πŸš€ Deployment stack

Nginx (reverse proxy, serves static, HTTPS) β†’ Gunicorn (WSGI, multiple workers) β†’ Flask app

app.run() is single-threaded dev server. Never use in production. See Flask Basics & Application Setup.

πŸ¦„ Gunicorn

pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 "app:create_app()"

-w 4 = 4 worker processes. Rough formula: (2 Γ— CPU cores) + 1.

🌐 Nginx reverse proxy

server {
    listen 80;
    server_name myapp.com;
 
    location /static/ {
        alias /path/to/myproject/app/static/;
    }
 
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Static files served directly by Nginx, not Flask β€” much faster.

🐳 Dockerized deployment

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:create_app()"]

βœ… Pre-launch checklist

  • DEBUG = False
  • SECRET_KEY = long random value from env var, not hardcoded
  • No secrets committed to version control
  • SESSION_COOKIE_SECURE = True if serving HTTPS
  • Error handlers return generic messages, log full detail server-side (see Flask Error Handling & Logging)

πŸ”— Back to

Flask