Flask Testing Basics
Testing a Flask application means running your routes and checking that they return the expected responses. Flask provides a built-in test client that simulates HTTP requests without starting a real server. This lets you catch bugs before users do.
Why Test Flask Apps
Every time you change code, you risk breaking something that worked before. Tests run automatically and tell you immediately if a change caused a regression. A well-tested application lets you refactor confidently and deploy without fear.
The Test Client
Flask's test client simulates browser requests. You call client.get('/route') or client.post('/route', data={...}) and get back a response object you can inspect.
from app import create_app
app = create_app('testing')
def test_homepage():
client = app.test_client()
response = client.get('/')
assert response.status_code == 200
assert b'Welcome' in response.dataUsing pytest
pytest is the standard testing framework for Python. Install it:
pip install pytestOrganize tests in a tests/ folder:
myapp/ ├── app/ ├── tests/ │ ├── conftest.py ← shared fixtures │ ├── test_routes.py ← route tests │ └── test_models.py ← model tests └── run.py
Fixtures in conftest.py
Fixtures are reusable setup functions. pytest automatically passes them to any test function that requests them by name:
# tests/conftest.py
import pytest
from app import create_app, db
@pytest.fixture
def app():
app = create_app('testing')
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture
def client(app):
return app.test_client()
@pytest.fixture
def runner(app):
return app.test_cli_runner()Writing Your First Tests
# tests/test_routes.py
def test_home_page_loads(client):
response = client.get('/')
assert response.status_code == 200
def test_about_page_loads(client):
response = client.get('/about')
assert response.status_code == 200
def test_nonexistent_page_returns_404(client):
response = client.get('/this-does-not-exist')
assert response.status_code == 404The Response Object
| Attribute | Type | What It Contains |
|---|---|---|
response.status_code | int | HTTP status (200, 404, etc.) |
response.data | bytes | Response body as bytes |
response.get_json() | dict | Parsed JSON body |
response.headers | dict | Response headers |
response.location | str | Redirect URL (for 3xx responses) |
Testing POST Requests
def test_contact_form_submission(client):
response = client.post('/contact', data={
'name': 'Alice',
'email': 'alice@example.com',
'message': 'Hello from the test!'
})
assert response.status_code == 302 # redirect after success
assert '/thank-you' in response.locationTesting JSON API Endpoints
def test_api_returns_json(client):
response = client.get('/api/products')
assert response.status_code == 200
assert response.content_type == 'application/json'
data = response.get_json()
assert isinstance(data, list)
def test_api_create_product(client):
response = client.post(
'/api/products',
json={'name': 'Test Product', 'price': 9.99}
)
assert response.status_code == 201
data = response.get_json()
assert data['name'] == 'Test Product'Running Tests
# Run all tests
pytest
# Run with verbose output
pytest -v
# Run a specific file
pytest tests/test_routes.py
# Run tests with a keyword
pytest -k "test_api"Summary
Flask's test client simulates HTTP requests so you can test routes without a running server. Use pytest with fixtures to set up a clean test app and database for each test. Check response.status_code, response.data, and response.get_json() to verify your routes behave correctly. Run pytest after every code change to catch regressions immediately.
