YouTip LogoYouTip

Flask Testing

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

← Flask Api Application ObjectFlask Config β†’