Ответ 1
Так как Django 1.3 имеет assertNumQueries, доступный именно для этой цели.
Я пытаюсь выяснить количество запросов, выполняемых функцией утилиты. Я написал unit test для этой функции, и функция работает хорошо. То, что я хотел бы сделать, - отслеживать количество 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>)
EDIT: я узнал, что для этого есть ожидающий Django запрос функции. Однако билет все еще открыт. А пока есть еще один способ сделать это?
Так как Django 1.3 имеет assertNumQueries, доступный именно для этой цели.
Ответ Vinay правильный, с одним незначительным дополнением.
Django unit test framework фактически устанавливает DEBUG в False, когда он запускается, поэтому независимо от того, что у вас есть в settings.py
, в вашем unit test ничего не будет заполнено в connection.queries
, если вы не включите режим отладки, Документы Django объясняют обоснование для этого как:
Независимо от значения параметра DEBUG в вашем файле конфигурации, все тесты Django работают с DEBUG = False. Это делается для того, чтобы наблюдаемый результат вашего кода соответствовал тому, что будет видно в настройках производства.
Если вы уверены, что включение отладки не повлияет на ваши тесты (например, если вы специально тестируете удары БД, как вам кажется, это решение временно отключить отладку в unit test, затем установите его обратно:
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
Если у вас DEBUG
установлено значение True в вашем settings.py
(предположительно, в тестовой среде), вы можете считать запросы, выполненные в вашем тесте, следующим образом:
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) здесь, у вас есть метод 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()
Вы также можете рассмотреть вопрос о сбросе запросов на setUp/tearDown, чтобы гарантировать, что запросы reset для каждого теста вместо того, чтобы делать это в предложении finally, но этот способ более явный (хотя и более подробный), или вы можете использовать reset_queries в предложении try столько раз, сколько нужно, чтобы подсчитывать запросы с 0.
Если вы не хотите использовать 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
Если вы используете 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')