Flask Testing | Online Tutorial
Testing is the foundation of ensuring code quality.
Flask provides a built-in testing client, and with pytest, you can efficiently write and run tests.
Test Client β test_client
Flask's test_client() method creates a simulated HTTP client that can send requests without starting the server:
Example
# File path: test_demo.py (test in Python interactive environment)
from app import create_app
# Create app instance for testing
app = create_app()
# Create test client
with app.test_client() as client:
# Send GET request
response = client.get("/")
print(response.status_code) # 200
print(response.data[:100]) # First 100 bytes of response body
# Send POST request with JSON data
response = client.post("/api/posts",
json={"title": "Online Tutorial", "body": "Content", "author_id": 1})
print(response.status_code) # 201
print(response.get_json()) # Parse JSON response
pytest Integration
pytest is the standard testing framework in the Python community, and it works very well with Flask.
Install pytest
(.venv) $ pip install pytest
Write Tests β conftest.py (Shared Fixtures)
Use conftest.py to create reusable test fixtures:
Example
# File path: tests/conftest.py
import os
import tempfile
import pytest
from app import create_app
from db import init_db, get_db
@pytest.fixture
def app():
"""Create app instance for testing, using temporary database"""
# Create temporary file as test database
db_fd, db_path = tempfile.mkstemp()
# Create app, override database path to temporary file
app = create_app()
app.config = db_path
app.config = True # Enable testing mode
# Initialize test database schema
with app.app_context():
init_db()
yield app
# Cleanup after test: close and delete temporary database file
os.close(db_fd)
os.unlink(db_path)
@pytest.fixture
def client(app):
"""Create test client"""
return app.test_client()
@pytest.fixture
def runner(app):
"""Create CLI test runner"""
return app.test_cli_runner()
Test Routes
Example
# File path: tests/test_app.py
def test_home_page(client):
"""Test if home page returns normally"""
response = client.get("/")
assert response.status_code == 200
# Check if page contains expected keyword
assert b"TUTORIAL" in response.data
def test_404_page(client):
"""Test accessing non-existent page"""
response = client.get("/this-page-does-not-exist")
assert response.status_code == 404
Run tests:
(.venv) $ pytest tests/test_app.py -v
==================================== tests/test_app.py::test_home_page PASSED
==================================== tests/test_app.py::test_404_page PASSED
====================================
Test JSON API
Example
# File path: tests/test_api.py
def test_create_post(client):
"""Test create post API"""
response = client.post("/api/posts", json={
"title": "TUTORIAL Test Article",
"body": "This is test content",
"author_id": 1
})
# Successful creation should return 201
assert response.status_code == 201
data = response.get_json()
assert data == "TUTORIAL Test Article"
assert "id" in data
def test_create_post_without_title(client):
"""Test returns 400 error when title is empty"""
response = client.post("/api/posts", json={
"title": "",
"body": "Content",
"author_id": 1
})
assert response.status_code == 400
assert b"error" in response.data
def test_get_posts(client):
"""Test get post list"""
# First create a post
client.post("/api/posts", json={
"title": "Article A", "body": "Content A", "author_id": 1
})
# Get list
response = client.get("/api/posts")
assert response.status_code == 200
data = response.get_json()
assert len(data) >= 1
def test_delete_post(client):
"""Test delete post"""
# First create
rv = client.post("/api/posts", json={
"title": "To be deleted", "body": "Content", "author_id": 1
})
post_id = rv.get_json()
# Then delete
rv = client.delete(f"/api/posts/{post_id}")
assert rv.status_code == 200
# Confirm deleted
rv = client.get(f"/api/posts/{post_id}")
assert rv.status_code == 404
Test Session
Test functions that require Session, such as login:
Example
# File path: tests/test_auth.py
def test_login(client):
"""Test login flow"""
# Send login request
response = client.post("/auth/login", data={
"username": "testuser",
"password": "testpass"
}, follow_redirects=True) # follow_redirects automatically follows redirects
assert response.status_code == 200
def test_session_transaction(client):
"""Directly manipulate session for testing"""
with client.session_transaction() as session:
# Directly set value in session to simulate logged-in state
session = "tutorial"
# Now accessing home page should show logged-in state
response = client.get("/")
assert b"tutorial" in response.data
client.session_transaction() is a very useful testing tool β it allows
YouTip