Django: Gibt es eine Möglichkeit, SQL-Abfragen von einem Unit-Test zu zählen?
-
12-09-2019 - |
Frage
Ich versuche, die Anzahl der Abfragen durch eine Nutzenfunktion ausgeführt, um herauszufinden. Ich habe einen Komponententest für diese Funktion geschrieben und die Funktion gut funktioniert. Was ich möchte, ist die Anzahl der SQL-Abfragen durch die Funktion ausgeführt, um den Überblick, so dass ich sehen kann, ob es eine Verbesserung nach einigem Refactoring ist.
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: Ich fand heraus, dass es eine Django anhängig Feature-Anfrage für diese. Allerdings ist das Ticket noch offen. In der Zwischenzeit gibt es eine andere Art und Weise, um dies zu?
Lösung
Da Django 1.3 gibt es eine assertNumQueries verfügbar genau für diesen Zweck.
Andere Tipps
Vinay Antwort richtig ist, mit einem kleinen Zusatz.
Djangos Unit-Test-Framework DEBUG auf False tatsächlich einstellt, wenn es läuft, also egal, was Sie in settings.py
haben, werden Sie nichts in connection.queries
in Ihrem Unit-Test bevölkert haben, wenn Sie wieder aktivieren Debug-Modus. Die Django docs erklärt die Begründung für diese als:
Unabhängig vom Wert der DEBUG-Einstellung in der Konfigurationsdatei, die alle Django-Tests mit DEBUG ausführen = False. Damit soll sichergestellt werden, dass die beobachtete Ausgabe des Codes übereinstimmt, was in einer Produktionsumgebung zu sehen sein wird.
Wenn Sie sicher sind, dass die Debug ermöglicht wird Ihre Tests beeinflussen (zB wenn Sie speziell zu test DB trifft, wie es klingt wie Sie sind), ist die Lösung, um vorübergehend wieder aktivieren Debug in Ihrem Gerät zu testen, legen sie es dann wieder später:
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
Wenn Sie pytest
verwenden, pytest-django
hat django_assert_num_queries Halterung für diesen Zweck:
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')
Wenn Sie in Ihrem DEBUG
settings.py
auf True gesetzt haben (vermutlich so in der Testumgebung), dann können Sie Abfragen in Ihrem Test ausgeführt zählen wie folgt:
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)
In der modernen Django (> = 1.8) es ist gut dokumentiert (es ist auch für 1.7 dokumentiert) hier , haben Sie die Methode reset_queries statt Zuweisung connection.queries = [] , die in der Tat einen Fehler erzieht, dass so etwas funktioniert auf 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()
Sie können sich auch Abfragen auf Setup / Teardown Zurücksetzen Abfragen für jeden Test zurückgesetzt, um sicherzustellen, anstatt es zu tun auf finally, aber auf diese Weise ist expliziter (obwohl ausführlicher), oder Sie können verwenden reset_queries in der try-Klausel so oft wie Sie Abfragen müssen auswerten von 0 zu zählen.
Wenn Sie nicht verwenden wollen Testcase (mit assertNumQueries ) oder Einstellungen ändern DEBUG = True, können Sie Kontextmanager CaptureQueriesContext (das gleiche wie assertNumQueries verwenden).
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