高校物理161885 views
中学社会669775 views
教育149914 views
Computer369599 views
小学社会311307 views
LaTeX964644 views
雑学1474079 views
小学理科721270 views
高校倫理1443364 views
中学理科1632943 views
Help
Tools

English

Flask のテスト戦略と pytest の活用

Flask アプリケーションのテストは pytest を使うと効率的に書ける。テストクライアント、フィクスチャ、モックを活用したテスト戦略を解説する。

基本的なテスト設定

# tests/conftest.py
import pytest
from app import create_app
from app.extensions import db

@pytest.fixture
def app():
    app = create_app('testing')
    with app.app_context():
        db.create_all()
        yield app
        db.drop_all()

@pytest.fixture
def client(app):
    return app.test_client()

@pytest.fixture
def runner(app):
    return app.test_cli_runner()

テストクライアントの使い方

# tests/test_views.py
def test_index(client):
    response = client.get('/')
    assert response.status_code == 200
    assert b'Welcome' in response.data

def test_login(client):
    response = client.post('/login', data={
        'username': 'alice',
        'password': 'secret'
    })
    assert response.status_code == 302  # リダイレクト

セッションを使ったテスト

def test_authenticated_access(client):
    with client.session_transaction() as sess:
        sess['user_id'] = 1
    
    response = client.get('/dashboard')
    assert response.status_code == 200

JSON API のテスト

def test_api_create_user(client):
    response = client.post('/api/users',
        json={'name': 'Alice', 'email': 'alice@example.com'},
        content_type='application/json'
    )
    assert response.status_code == 201
    data = response.get_json()
    assert data['name'] == 'Alice'

データベースを使ったテスト

# tests/conftest.py
@pytest.fixture
def sample_user(app):
    from app.models import User
    user = User(username='testuser', email='test@example.com')
    user.set_password('password')
    db.session.add(user)
    db.session.commit()
    return user

# tests/test_user.py
def test_user_login(client, sample_user):
    response = client.post('/login', data={
        'username': 'testuser',
        'password': 'password'
    })
    assert response.status_code == 302

モックの活用

from unittest.mock import patch

def test_send_email(client, sample_user):
    with patch('app.services.email_service.send_email') as mock_send:
        mock_send.return_value = True
        response = client.post('/reset-password', data={
            'email': 'test@example.com'
        })
        assert response.status_code == 200
        mock_send.assert_called_once()

カバレッジの計測

pip install pytest-cov
pytest --cov=app tests/

テストの構成

tests/
├── conftest.py           # 共通フィクスチャ
├── test_views.py         # ビューのテスト
├── test_api.py           # API のテスト
├── test_models.py        # モデルのテスト
├── test_services.py      # サービス層のテスト
└── test_integration.py   # 統合テスト

ファクトリを使ったテストデータ

# tests/factories.py
from app.models import User

class UserFactory:
    _counter = 0
    
    @classmethod
    def create(cls, **kwargs):
        cls._counter += 1
        defaults = {
            'username': f'user{cls._counter}',
            'email': f'user{cls._counter}@example.com'
        }
        defaults.update(kwargs)
        user = User(**defaults)
        db.session.add(user)
        db.session.commit()
        return user

pytest とフィクスチャを活用すれば、テストコードの重複を減らしつつ、包括的なテストを実現できる。