Джанго: есть ли способ подсчета SQL-запросов из модульного теста? - PullRequest
44 голосов
/ 10 августа 2009

Я пытаюсь выяснить количество запросов, выполненных функцией полезности. Я написал модульный тест для этой функции, и функция работает хорошо. Я хотел бы отследить количество 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 . Однако билет все еще открыт. В то же время есть ли другой способ пойти по этому поводу?

Ответы [ 6 ]

54 голосов
/ 11 октября 2011

Начиная с Django 1.3 существует assertNumQueries , доступный именно для этой цели.

40 голосов
/ 10 августа 2009

Ответ Винай правильный, с одним незначительным добавлением.

Среда модульного тестирования 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
7 голосов
/ 05 июня 2017

Если вы используете 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')
4 голосов
/ 10 августа 2009

Если у вас 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)
3 голосов
/ 29 августа 2015

В современном 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, чтобы гарантировать, что запросы сбрасываются для каждого теста, вместо того, чтобы делать это в предложении finally, но этот способ более явный (хотя и более подробный), или вы можете использовать reset_queries в предложении try столько раз, сколько нужно, чтобы оценить количество запросов, начиная с 0.

2 голосов
/ 25 августа 2016

Если вы не хотите использовать TestCase (с assertNumQueries ) или изменить настройки на DEBUG = True, вы можете использовать менеджер контекста CaptureQueriesContext (такой же, как assertNumQueries using).

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

Настройки дБ

...