姜戈:有没有办法计算单元测试中的 SQL 查询数量?
-
12-09-2019 - |
题
我试图找出实用函数执行的查询数量。我已经为此函数编写了单元测试,并且该函数运行良好。我想要做的是跟踪该函数执行的 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 功能要求 为了这。然而,门票仍然开放。与此同时,还有其他方法可以解决这个问题吗?
解决方案
由于Django的1.3存在 assertNumQueries使用正好用于该目的。
其他提示
维奈的响应是正确的,与一个较小的加成。
Django的单元测试框架实际上是设置DEBUG为False,在运行时,所以无论你在settings.py
,你不会有任何填充在connection.queries
在你的单元测试,除非你重新启用调试模式。 Django文档解释了这个作为理由:
无论在配置文件中的调试设置的值的,所有的Django测试与调试运行=假。这是为了确保代码的所观察到的输出相匹配什么会在生产设置中看到。
如果您确信启用调试不会影响你的测试(比如,如果你在专门测试DB命中,因为它听起来像你是),解决的办法是在单元测试暂时重新启用调试,然后将其设置回后:
def test_myself(self):
from django.conf import settings
from django.db import connection
settings.DEBUG = True
connection.queries = []
# Test code as normal
self.assert_(connection.queries)
settings.DEBUG = False
如果使用的是pytest
,pytest-django
具有 django_assert_num_queries 夹具用于该目的:
def test_queries(django_assert_num_queries):
with django_assert_num_queries(3):
Item.objects.create('foo')
Item.objects.create('bar')
Item.objects.create('baz')
如果您已经DEBUG
在settings.py
设置为True(大概所以在测试环境中),那么你可以指望在测试执行的查询如下:
from django.db import connection
class DoSomethingTests(django.test.TestCase):
def test_something_or_other(self):
num_queries_old = len(connection.queries)
do_something_in_the_database()
num_queries_new = len(connection.queries)
self.assertEqual(n, num_queries_new - num_queries_old)
在现代 Django (>=1.8) 中,它有很好的文档记录(1.7 也有文档记录) 这里, ,你有方法 重置查询 而不是分配 连接.查询=[] 这确实引发了一个错误,类似的东西适用于 django>=1.8:
class QueriesTests(django.test.TestCase):
def test_queries(self):
from django.conf import settings
from django.db import connection, reset_queries
try:
settings.DEBUG = True
# [... your ORM code ...]
self.assertEquals(len(connection.queries), num_of_expected_queries)
finally:
settings.DEBUG = False
reset_queries()
您还可以考虑在 setUp/tearDown 上重置查询,以确保为每个测试重置查询,而不是在 finally 子句上重置查询,但这种方式更明确(尽管更冗长),或者您可以使用 重置查询 在 try 子句中添加任意次数,以评估从 0 开始计数的查询。
如果你不想使用 TestCase (带有 断言查询数量)或将设置更改为 DEBUG=True,您可以使用上下文管理器 CaptureQueriesContext (与 断言查询数量 使用)。
from django.db import ConnectionHandler
from django.test.utils import CaptureQueriesContext
DB_NAME = "default" # name of db configured in settings you want to use - "default" is standard
connection = ConnectionHandler()[DB_NAME]
with CaptureQueriesContext(connection) as context:
... # do your thing
num_queries = context.initial_queries - context.final_queries
assert num_queries == expected_num_queries