在Django中,我经常声明应该进行的查询次数,以便单元测试能够捕获新的N + 1查询问题
from django import db
from django.conf import settings
settings.DEBUG=True
class SendData(TestCase):
def test_send(self):
db.connection.queries = []
event = Events.objects.all()[1:]
s = str(event) # QuerySet is lazy, force retrieval
self.assertEquals(len(db.connection.queries), 2)
在SQLAlchemy中,通过设置echo
标志来启用对STDOUT的跟踪
发动机
engine.echo=True
编写计算SQLAlchemy查询数量的测试的最佳方法是什么?
class SendData(TestCase):
def test_send(self):
event = session.query(Events).first()
s = str(event)
self.assertEquals( ... , 2)
答案 0 :(得分:9)
使用SQLAlchemy Core Events记录/跟踪已执行的查询(您可以从单元测试中附加它,这样它们就不会影响您在实际应用程序上的性能:
event.listen(engine, "before_cursor_execute", catch_queries)
现在编写函数catch_queries
,其方式取决于您的测试方式。例如,您可以在测试语句中定义此函数:
def test_something(self):
stmts = []
def catch_queries(conn, cursor, statement, ...):
stmts.append(statement)
# Now attach it as a listener and work with the collected events after running your test
上述方法只是一个灵感。对于扩展的情况,您可能希望拥有在每次测试后清空的事件的全局缓存。原因是在0.9(当前开发)之前没有用于删除事件侦听器的API。因此,创建一个访问全局列表的全局侦听器。
答案 1 :(得分:9)
我为此目的创建了一个上下文管理器类:
class DBStatementCounter(object):
"""
Use as a context manager to count the number of execute()'s performed
against the given sqlalchemy connection.
Usage:
with DBStatementCounter(conn) as ctr:
conn.execute("SELECT 1")
conn.execute("SELECT 1")
assert ctr.get_count() == 2
"""
def __init__(self, conn):
self.conn = conn
self.count = 0
# Will have to rely on this since sqlalchemy 0.8 does not support
# removing event listeners
self.do_count = False
sqlalchemy.event.listen(conn, 'after_execute', self.callback)
def __enter__(self):
self.do_count = True
return self
def __exit__(self, *_):
self.do_count = False
def get_count(self):
return self.count
def callback(self, *_):
if self.do_count:
self.count += 1
答案 2 :(得分:1)
使用flask_sqlalchemy.get_debug_queries() btw的方法如何。这是Flask Debug Toolbar内部检查其source
使用的方法from flask_sqlalchemy import get_debug_queries
def test_list_with_assuring_queries_count(app, client):
with app.app_context():
# here generating some test data
for _ in range(10):
notebook = create_test_scheduled_notebook_based_on_notebook_file(
db.session, owner='testing_user',
schedule={"kind": SCHEDULE_FREQUENCY_DAILY}
)
for _ in range(100):
create_test_scheduled_notebook_run(db.session, notebook_id=notebook.id)
with app.app_context():
# after resetting the context call actual view we want asserNumOfQueries
client.get(url_for('notebooks.personal_notebooks'))
assert len(get_debug_queries()) == 3
请记住,要重置上下文并计数,您必须在要测量的确切内容之前致电with app.app_context()
。