Подтвердить что ты не робот

Django: есть ли способ подсчета запросов SQL из unit test?

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

4b9b3361

Ответ 1

Так как Django 1.3 имеет assertNumQueries, доступный именно для этой цели.

Ответ 2

Ответ 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

Ответ 3

Если у вас 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)

Ответ 4

В современном 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.

Ответ 5

Если вы не хотите использовать 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

настройки db

Ответ 6

Если вы используете 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')