Man*_*dan 49 django django-orm django-testing
我试图找出实用程序函数执行的查询数.我已经为这个函数编写了一个单元测试,并且该函数运行良好.我想要做的是跟踪函数执行的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>)
Run Code Online (Sandbox Code Playgroud)
编辑:我发现有一个待定的Django 功能请求.但是票仍然是开放的.与此同时还有另一种方法可以解决这个问题吗?
Jar*_*die 41
Vinay的回答是正确的,只有一个小的补充.
Django的单元测试框架在运行时实际上将DEBUG设置为False,因此无论您settings.py使用什么,connection.queries除非重新启用调试模式,否则您的单元测试中不会包含任何内容.Django文档解释了这个的基本原理:
无论配置文件中DEBUG设置的值如何,所有Django测试都以DEBUG = False运行.这是为了确保您观察到的代码输出与生产设置中的内容相匹配.
如果您确定启用调试不会影响您的测试(例如,如果您专门测试数据库命中,就像您听到的那样),解决方案是在您的单元测试中暂时重新启用调试,然后设置它之后回来:
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
Run Code Online (Sandbox Code Playgroud)
如果您不想使用 TestCase(带有assertNumQueries)或将设置更改为 DEBUG=True,则可以使用上下文管理器 CaptureQueriesContext(与使用assertNumQueries相同)。
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
Run Code Online (Sandbox Code Playgroud)
这是带有 AssertNumQueriesLessThan 的上下文管理器的工作原型
import json
from contextlib import contextmanager
from django.test.utils import CaptureQueriesContext
from django.db import connections
@contextmanager
def withAssertNumQueriesLessThan(self, value, using='default', verbose=False):
with CaptureQueriesContext(connections[using]) as context:
yield # your test will be run here
if verbose:
msg = "\r\n%s" % json.dumps(context.captured_queries, indent=4)
else:
msg = None
self.assertLess(len(context.captured_queries), value, msg=msg)
Run Code Online (Sandbox Code Playgroud)
它可以简单地用在单元测试中,例如检查每个 Django REST API 调用的查询数量
with self.withAssertNumQueriesLessThan(10):
response = self.client.get('contacts/')
self.assertEqual(response.status_code, 200)
Run Code Online (Sandbox Code Playgroud)
您还可以提供精确的数据库using,verbose如果您想将实际查询的列表漂亮地打印到标准输出
在现代 Django (>=1.8) 中,它有很好的文档记录(它也记录在 1.7 中)here,你有方法reset_queries而不是分配connection.queries=[]这确实会引发错误,类似的东西在 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()
Run Code Online (Sandbox Code Playgroud)
您也可以考虑在 setUp/tearDown 上重置查询以确保为每个测试重置查询而不是在 finally 子句上执行此操作,但这种方式更明确(虽然更详细),或者您可以在 try 子句中多次使用reset_queries因为您需要评估从 0 开始计数的查询。
小智 7
如果您使用的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')
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17420 次 |
| 最近记录: |