SQLAlchemyでユニットテストにおけるクエリ数をカウントする方法
SQLAlchemyは、Pythonでオブジェクト関係マッピング(ORM)を行うためのライブラリです。ユニットテストにおいて、SQLAlchemyで実行されたクエリ数をカウントすることは、パフォーマンスの問題やテストカバレッジの確認に役立ちます。
方法
SQLAlchemyでクエリ数をカウントするには、いくつかの方法があります。
monkeypatchモジュールを使う
monkeypatch
モジュールを使って、sqlalchemy.engine.Engine
クラスのexecute
メソッドをパッチすることができます。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from monkeypatch import MonkeyPatch
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
# パッチを適用
mp = MonkeyPatch()
mp.setattr(engine.execute, "count", 0)
# テストコード
session.query(User).all()
# パッチを解除
mp.undo()
# クエリ数を確認
print(engine.execute.count)
event.listenを使う
event.listen
を使って、before_execute
イベントをリッスンすることができます。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.events import before_execute
Base = declarative_base()
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
# クエリ数を格納する変数
query_count = 0
def before_execute_handler(mapper, connection, statement, parameters, context):
global query_count
query_count += 1
before_execute(engine, mapper=Base, handler=before_execute_handler)
# テストコード
session.query(User).all()
# クエリ数を確認
print(query_count)
sqlalchemy.ext.declarative.api.Profilerを使う
sqlalchemy.ext.declarative.api.Profiler
を使うと、実行されたSQL文とその統計情報を取得することができます。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative.api import Profiler
Base = declarative_base()
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
profiler = Profiler()
session = sessionmaker(bind=engine, profiler=profiler)()
# テストコード
session.query(User).all()
# 実行されたSQL文と統計情報を確認
for query in profiler.get_statement_executions():
print(query.statement)
print(query.duration)
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from monkeypatch import MonkeyPatch
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
# パッチを適用
mp = MonkeyPatch()
mp.setattr(engine.execute, "count", 0)
# テストコード
session.query(User).all()
# パッチを解除
mp.undo()
# クエリ数を確認
print(engine.execute.count)
解説
create_engine
を使って、SQLiteデータベースへの接続を作成します。sessionmaker
を使って、セッションを作成します。- テストコードを実行します。
- パッチを解除します。
engine.execute.count
を使って、クエリ数を取得します。
実行結果
1
monkeypatch
モジュールは、テストコードでのみ使用することを推奨します。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.events import before_execute
Base = declarative_base()
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
# クエリ数を格納する変数
query_count = 0
def before_execute_handler(mapper, connection, statement, parameters, context):
global query_count
query_count += 1
before_execute(engine, mapper=Base, handler=before_execute_handler)
# テストコード
session.query(User).all()
# クエリ数を確認
print(query_count)
before_execute_handler
という関数を作成し、その中でクエリ数をカウントします。query_count
を使って、クエリ数を取得します。
メリット
monkeypatch
モジュールを使うよりもコードがシンプルになる。
- 特定のMapperクラスに対してのみ有効。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative.api import Profiler
Base = declarative_base()
engine = create_engine("sqlite:///:memory:")
session = sessionmaker(bind=engine)()
profiler = Profiler()
session = sessionmaker(bind=engine, profiler=profiler)()
# テストコード
session.query(User).all()
# 実行されたSQL文と統計情報を確認
for query in profiler.get_statement_executions():
print(query.statement)
print(query.duration)
sqlalchemy.ext.declarative.api.Profiler
を使って、Profilerオブジェクトを作成します。sessionmaker
を使って、Profilerオブジェクトを渡してセッションを作成します。profiler.get_statement_executions
を使って、実行されたSQL文とその統計情報を取得します。
- 実行されたSQL文とその統計情報を確認できる。
- コードが複雑になる。
sqlalchemy