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/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 とフィクスチャを活用すれば、テストコードの重複を減らしつつ、包括的なテストを実現できる。