Django:有没有办法计算单元测试中的 SQL 查询数量?
我试图找出实用函数执行的查询数量。 我已经为此函数编写了单元测试,并且该函数运行良好。 我想要做的是跟踪该函数执行的 SQL 查询的数量,以便我可以查看一些重构后是否有任何改进。
def do_something_in_the_database():
# Does something in the database
# return result
class DoSomethingTests(django.test.TestCase):
def test_function_returns_correct_values(self):
self.assertEqual(n, <number of SQL queries executed>)
编辑:我发现有一个待处理的 Django 功能请求。 然而,门票仍然开放。 与此同时,还有其他方法可以解决这个问题吗?
I am trying to find out the number of queries executed by a utility function. I have written a unit test for this function and the function is working well. What I would like to do is track the number of SQL queries executed by the function so that I can see if there is any improvement after some refactoring.
def do_something_in_the_database():
# Does something in the database
# return result
class DoSomethingTests(django.test.TestCase):
def test_function_returns_correct_values(self):
self.assertEqual(n, <number of SQL queries executed>)
EDIT: I found out that there is a pending Django feature request for this. However the ticket is still open. In the meantime is there another way to go about this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
如果你想使用装饰器,有一个很好的要点:
If you want to use a decorator for that there is a nice gist:
如果您在
settings.py
中将DEBUG
设置为 True(大概在您的测试环境中如此),那么您可以对测试中执行的查询进行计数,如下所示:If you have
DEBUG
set to True in yoursettings.py
(presumably so in your test environment) then you can count queries executed in your test as follows:这是上下文管理器 withAssertNumQueriesLessThan 的工作原型,
它可以简单地在您的单元测试中使用,例如检查每个 Django REST API 调用的查询数量 数据库
如果您想要将实际查询的列表漂亮地打印到标准输出,您还可以
using
和verbose
提供精确的Here is the working prototype of context manager withAssertNumQueriesLessThan
It can be simply used in your unit tests for example for checking the number of queries per Django REST API call
Also you can provide exact DB
using
andverbose
if you want to pretty-print list of actual queries to stdout在现代 Django (>=1.8) 中,它有详细的文档记录(1.7 也有文档记录)此处,您可以使用方法reset_queries,而不是分配connection.queries=[ ] 这确实引发了一个错误,类似于 django>=1.8 上的情况:
您还可以考虑在 setUp/tearDown 上重置查询,以确保为每个测试重置查询,而不是在 finally 子句上执行此操作,但这way 更明确(尽管更详细),或者您可以根据需要在 try 子句中使用 reset_queries 多次来评估从 0 开始计数的查询。
In modern Django (>=1.8) it's well documented (it's also documented for 1.7) here, you have the method reset_queries instead of assigning connection.queries=[] which indeed is raising an error, something like that works on django>=1.8:
You may also consider resetting queries on setUp/tearDown to ensure queries are reset for each test instead of doing it on finally clause, but this way is more explicit (although more verbose), or you can use reset_queries in the try clause as many times as you need to evaluate queries counting from 0.
如果您不想使用 TestCase (使用 assertNumQueries)或将设置更改为 DEBUG=True,您可以使用上下文管理器 CaptureQueriesContext (与 assertNumQueries 使用)。
数据库设置
If you don't want use TestCase (with assertNumQueries) or change settings to DEBUG=True, you can use context manager CaptureQueriesContext (same as assertNumQueries using).
db settings
如果您使用 pytest,则 pytest-django 具有 django_assert_num_queries 用于此目的的固定装置:
If you are using
pytest
,pytest-django
has django_assert_num_queries fixture for this purpose:Vinay 的回答是正确的,但有一点补充。
Django 的单元测试框架实际上在运行时将 DEBUG 设置为 False,因此无论您在
settings.py
中有什么,您都不会在connection.queries
中填充任何内容。单元测试,除非您重新启用调试模式。 Django 文档将基本原理解释为:如果您确定启用调试不会影响您的测试(例如,如果您专门测试数据库命中,就像听起来那样),解决方案是在单元测试中暂时重新启用调试,然后设置它之后回来:
Vinay's response is correct, with one minor addition.
Django's unit test framework actually sets DEBUG to False when it runs, so no matter what you have in
settings.py
, you will not have anything populated inconnection.queries
in your unit test unless you re-enable debug mode. The Django docs explain the rationale for this as:If you're certain that enabling debug will not affect your tests (such as if you're specifically testing DB hits, as it sounds like you are), the solution is to temporarily re-enable debug in your unit test, then set it back afterward:
从 Django 1.3 开始,有一个 assertNumQueries 正是用于此目的。
使用它的一种方法(从 Django 3.2 开始)是作为上下文管理器:
Since Django 1.3 there is a assertNumQueries available exactly for this purpose.
One way to use it (as of Django 3.2) is as a context manager: