Flask routes work until they stop working, usually at the worst possible time. Unit tests catch regressions before they reach production. Flask has a built-in test client that makes testing routes clean without spinning up a real server.
TL;DR: Write unit tests for Flask applications using the built-in test client: test routes, request handling, and use mocks for external dependencies.
Stack: Python, Flask, pytest, Flask test client
Level: Intermediate
Reading time: ~20 min
Setup
pip install pytest coverage pytest-cov flask
Example 1: Simple function tests
def get_hero_name(hero_id):
heroes = {1: 'Iron Man', 2: 'Captain America', 3: 'Thor', 4: 'Hulk', 5: 'Black Widow'}
return heroes.get(hero_id, 'Unknown Hero')
def is_avenger(hero_name):
avengers = {'Iron Man', 'Captain America', 'Thor', 'Hulk', 'Black Widow'}
return hero_name in avengers
from marvel import get_hero_name, is_avenger
def test_get_hero_name():
assert get_hero_name(1) == 'Iron Man'
assert get_hero_name(6) == 'Unknown Hero'
def test_is_avenger():
assert is_avenger('Iron Man') is True
assert is_avenger('Spider-Man') is False
pytest example1/test_marvel.py
Example 2: Tests with classes and coverage
pytest example2/test_marvel.py --cov=. --cov-report term-missing
Example 3: Mocking external HTTP requests
from unittest.mock import patch
@patch('marvel.requests.get')
def test_fetch_hero_info(mock_get):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {'name': 'Mocked Hero'}
hero_name = Marvel.fetch_hero_info(1)
assert hero_name == 'Mocked Hero'
Flask integration tests
import pytest
from app import app
@pytest.fixture
def client():
with app.test_client() as client:
yield client
def test_get_hero(client):
response = client.get('/hero/1')
data = response.get_json()
assert response.status_code == 200
assert data['hero_name'] == 'Iron Man'
def test_calculate_sum(client):
response = client.post('/calculate', json={'n1': 5, 'n2': 10, 'operation': 'sum'})
assert response.status_code == 200
assert response.get_json()['result'] == 15
def test_calculate_invalid_operation(client):
response = client.post('/calculate', json={'n1': 5, 'n2': 11, 'operation': 'subtract'})
assert response.status_code == 400
assert response.get_json()['error'] == 'Invalid operation'
conftest.py fix for imports
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
What you’ve built
A Flask testing reference covering simple function tests, class-based tests, mocked HTTP calls, and integration tests using the Flask test client.
Next steps
- Use app.config[“TESTING”] = True and a separate test database to isolate tests from development data.
- Test all HTTP methods, status codes, response bodies, and error cases. Don’t just test the happy path.
- Use conftest.py fixtures for the Flask app instance and database setup so they are shared across all test files.
Questions or feedback? Find me on LinkedIn or GitHub.