Skip to content

Commit 4562abe

Browse files
committed
Create "querycount" parameter
1 parent 3068be3 commit 4562abe

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

pytest_django/plugin.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ def pytest_addoption(parser):
8383
'Fail for invalid variables in templates.',
8484
type='bool', default=False)
8585

86+
group._addoption('--querycount',
87+
action='store', type=int, default=None, metavar='N',
88+
help='Show top N tests with most queries '
89+
'(N=0 for all).')
90+
8691

8792
def _exists(path, ignore=EnvironmentError):
8893
try:
@@ -317,6 +322,59 @@ def pytest_runtest_setup(item):
317322
_disable_class_methods(cls)
318323

319324

325+
@pytest.hookimpl(hookwrapper=True)
326+
def pytest_runtest_call(item):
327+
count_parameter = item.config.option.querycount
328+
if count_parameter is None:
329+
yield
330+
return
331+
332+
from django.test.utils import CaptureQueriesContext
333+
from django.db import connection
334+
335+
with CaptureQueriesContext(connection) as context:
336+
yield
337+
338+
item.add_report_section('call', 'queries', context.captured_queries)
339+
340+
341+
def pytest_terminal_summary(terminalreporter, exitstatus):
342+
count_parameter = terminalreporter.config.option.querycount
343+
if count_parameter is None:
344+
return
345+
346+
if count_parameter:
347+
header = 'top {} tests with most queries'.format(count_parameter)
348+
reports_slice = slice(None, count_parameter)
349+
else:
350+
header = 'top tests with most queries'
351+
reports_slice = slice(None, None)
352+
353+
terminalreporter.write_sep('=', header)
354+
355+
def get_query_count(report):
356+
sections = dict(report.sections)
357+
return len(sections.get('Captured queries call', []))
358+
359+
reports = (
360+
terminalreporter.stats.get('failed', []) +
361+
terminalreporter.stats.get('passed', [])
362+
)
363+
364+
reports.sort(key=get_query_count)
365+
reports.reverse()
366+
367+
for report in reports[reports_slice]:
368+
count = get_query_count(report)
369+
nodeid = report.nodeid.replace("::()::", "::")
370+
371+
terminalreporter.write_line('{count: <4} {when: <8} {nodeid}'.format(
372+
count=count,
373+
when=report.when,
374+
nodeid=nodeid
375+
))
376+
377+
320378
@pytest.fixture(autouse=True, scope='session')
321379
def django_test_environment(request):
322380
"""

tests/test_report.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
class TestQueryCount(object):
2+
"""Test report generated by --querycount parameter"""
3+
4+
def test_querycount_report_header(self, django_testdir):
5+
django_testdir.create_test_module('''
6+
def test_zero_queries():
7+
pass
8+
''')
9+
10+
result = django_testdir.runpytest_subprocess('--querycount=5')
11+
result.stdout.fnmatch_lines([
12+
'*== top 5 tests with most queries ==*'
13+
])
14+
15+
def test_header_not_set_without_parameter(self, django_testdir):
16+
django_testdir.create_test_module('''
17+
def test_zero_queries():
18+
pass
19+
''')
20+
21+
result = django_testdir.runpytest_subprocess()
22+
assert 'tests with most queries' not in result.stdout.str()
23+
24+
def test_querycount_report_lines(self, django_testdir):
25+
django_testdir.create_test_module('''
26+
import pytest
27+
from django.db import connection
28+
29+
@pytest.mark.django_db
30+
def test_one_query():
31+
with connection.cursor() as cursor:
32+
cursor.execute('SELECT 1')
33+
34+
assert True
35+
36+
@pytest.mark.django_db
37+
def test_two_queries():
38+
with connection.cursor() as cursor:
39+
cursor.execute('SELECT 1')
40+
cursor.execute('SELECT 1')
41+
42+
assert True
43+
44+
@pytest.mark.django_db
45+
def test_failed_one_query():
46+
with connection.cursor() as cursor:
47+
cursor.execute('SELECT 1')
48+
49+
assert False
50+
51+
def test_zero_queries():
52+
assert True
53+
''')
54+
55+
result = django_testdir.runpytest_subprocess('--querycount=3')
56+
lines = result.stdout.get_lines_after(
57+
'*top 3 tests with most queries*'
58+
)
59+
assert 'test_two_queries' in lines[0]
60+
assert 'test_one_query' in lines[1]
61+
assert 'test_failed' in lines[2]
62+
assert 'test_zero_queries' not in result.stdout.str()
63+
64+
def test_report_all_lines_on_querycount_zero(self, django_testdir):
65+
django_testdir.create_test_module('''
66+
import pytest
67+
from django.db import connection
68+
69+
@pytest.mark.django_db
70+
def test_one_query():
71+
with connection.cursor() as cursor:
72+
cursor.execute('SELECT 1')
73+
74+
assert True
75+
76+
@pytest.mark.django_db
77+
def test_two_queries():
78+
with connection.cursor() as cursor:
79+
cursor.execute('SELECT 1')
80+
cursor.execute('SELECT 1')
81+
82+
assert True
83+
''')
84+
85+
result = django_testdir.runpytest_subprocess('--querycount=0')
86+
lines = result.stdout.get_lines_after(
87+
'*top tests with most queries*'
88+
)
89+
assert 'test_two_queries' in lines[0]
90+
assert 'test_one_query' in lines[1]

0 commit comments

Comments
 (0)