Django: c'è un modo per contare query SQL da un test di unità?
-
12-09-2019 - |
Domanda
Sto cercando di scoprire il numero di query eseguite da una funzione di utilità. Ho scritto un test di unità per questa funzione e la funzione sta lavorando bene. Quello che vorrei fare è tenere traccia del numero di query SQL eseguite dalla funzione in modo che posso vedere se c'è qualche miglioramento dopo un po 'di refactoring.
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: ho scoperto che c'è un Django caratteristica richiesta attesa per questo. Tuttavia, il biglietto è ancora aperta. Nel frattempo c'è un altro modo per andare su questo?
Soluzione
Dal Django 1.3 c'è un assertNumQueries disponibili proprio per questo scopo.
Altri suggerimenti
La risposta di Vinay è corretta, con una piccola aggiunta.
framework di unit test di Django in realtà imposta DEBUG su False quando viene eseguito, quindi non importa quello che hai in settings.py
, non avrete nulla popolata connection.queries
nel vostro unit test a meno che non si ri-abilitare la modalità di debug. La documentazione Django spiegano la per questo come:
A prescindere dal valore dell'impostazione DEBUG nel file di configurazione, tutte Django test eseguiti con DEBUG = False. Questo per garantire che l'uscita osservata del codice corrisponde a quello che si vedrà in un ambiente di produzione.
Se si è certi che l'attivazione di debug non influenzerà i test (come ad esempio se si sta testando specificatamente DB colpisce, come suona come siete), la soluzione è temporaneamente riattivare il debug nel vostro unit test, quindi impostare nuovamente in seguito:
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
Se si utilizza pytest
, pytest-django
ha django_assert_num_queries apparecchio per questo scopo:
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')
Se avete DEBUG
impostato su True nel settings.py
(presumibilmente in modo nell'ambiente di prova), allora si può contare query eseguite nel test come segue:
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 Django moderna (> = 1.8) è ben documentato (è anche documentato per 1.7) qui , avete il metodo di reset_queries invece di assegnare connection.queries = [] , che in effetti sta sollevando un errore, qualcosa di simile che funziona su 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()
Si può anche prendere in considerazione il ripristino query su Setup / tearDown per garantire le query vengono reimpostati per ogni test invece di farlo sulla clausola finally, ma in questo modo è più esplicito (anche se più verbose), oppure è possibile utilizzare reset_queries nella clausola try tutte le volte che è necessario valutare le query contando da 0.
Se non si desidera utilizzare TestCase (con assertNumQueries ) o modificare le impostazioni per DEBUG = true, è possibile utilizzare contesto responsabile CaptureQueriesContext (stesso di assertNumQueries usando).
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