#5416 closed (fixed)
Add assertNumQueries() to testing framework
Reported by: | Adrian Holovaty | Owned by: | Alex Gaynor |
---|---|---|---|
Component: | Testing framework | Version: | dev |
Severity: | Keywords: | feature_request | |
Cc: | egmanoj@…, Alexander Koshelev, Mikhail Korobov | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
The Django testing framework should provide assertNumQueries()
, which would assert that a given action executed a given number of database queries. This should work at the view level ("view X uses 3 queries total") or the individual statement level ("model method X uses only 1 query").
This might have to be implemented as two methods -- a "start counting" method and a "stop counting" method:
def test_something(self): self.startCountingQueries() do_something_that_should_only_use_two_queries() self.assertNumQueries(2)
In this example, startCountingQueries()
would reset the counter to 0, and every query would be tallied from that point on. assertNumQueries()
would simply assert the query count was the given number.
Note that this depends on #5415, which provides signals for every SQL query.
Attachments (4)
Change History (26)
comment:1 by , 17 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 17 years ago
comment:3 by , 17 years ago
I am wondering whether we would want to provide this. The number of queries being run is an internal part of the framework, not something external code should ever rely on, nor expect to be stable.
comment:4 by , 17 years ago
In some cases, DDL in particular, this may be backend-dependent. For example, creating a model with an AutoField requires one query in PostgreSQL (CREATE TABLE) but three in Oracle (CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER).
comment:5 by , 17 years ago
Nis: While SQL statements are indeed an internal part of the framework, they're also something that developers should be able to test -- particular as we add "lazily loaded" features such as in #5420.
If you don't want to test the number of queries in your own unit tests, you don't have to. :)
comment:6 by , 17 years ago
Keywords: | feature_request added |
---|
comment:7 by , 16 years ago
We are now post-QSRF. If the patches get updated, can we fold #5415 and this into the mix?
comment:8 by , 16 years ago
This seems to be a very fragile test to provide, and changing the number of queries that something takes doesn't mean that it is functionally different. This seems a bit too specific for something to include in Django, especially considering that it is inherently knowing about internals.
follow-up: 11 comment:9 by , 16 years ago
@ericholscher: it's actually something that's worth testing. If it increases, you need to understand why. Django shouldn't be (and doesn't) throw around queries just for fun; it's something that's mostly under the developer's control. Agree with Adrian that this is useful to have (we already test this kind of thing a lot now and it's slightly crufty to do so).
comment:10 by , 16 years ago
Owner: | changed from | to
---|
comment:11 by , 15 years ago
Replying to mtredinnick:
(we already test this kind of thing a lot now and it's slightly crufty to do so).
Do you mind sharing how you do this? I am writing some test cases right now and would like to borrow your mechanism if you don't mind.
comment:12 by , 15 years ago
Cc: | added |
---|
by , 15 years ago
Attachment: | assert_number_of_queries.diff added |
---|
Patch adding assertNumberOfQueries method to TransactionTestCase.
comment:13 by , 15 years ago
Has patch: | set |
---|
comment:14 by , 15 years ago
I have added a custom method to TransactionTestCase
for asserting that a given callable executed exactly n queries. You can use it thus:
class HomePageTests(django.test.TestCase): def test_GET_home_page_uses_exactly_five_queries(self): self.assertNumberofQueries(5, self.client.get, reverse('home')) def test_POST_home_page_uses_exactly_seven_queries(self): self.assertNumberofQueries(7, self.client.post, reverse('home'), data = {'param': 'value'})
Hat tip: Jarret Hardie.
comment:15 by , 15 years ago
@Manoj - thanks for the patch, but I'm not sure this the right way to address the problem.
- Your patch requires enabling settings.DEBUG - an action that can have unintended (and potentially query induing) consequences.
- Your patch only works when wrapping a single callable. It's not something you could easily deploy in a test case, where you may want to do a query count check at several points in a complex test case. It also precludes (or makes impractical) the testing of a function that has side effects (so it can't be run twice) but also requires other test assertions.
As noted in the ticket comments, the preferred solution is to introduce a signal (vis #5415) and use that signal as the basis for logging the number of queries. This would allow logging regardless of the value of settings.DEBUG. The query count could be cleared at the test setUp; the assertion then validates that the callback has been invoked the right number of times. This would allow for checking the query count without the need to use callable wrapping.
There have been some recent Django-dev discussion about query logging, and the use of signals for this purpose was raised. It may be worth getting involved in this discussion if you're interested in pursuing this idea.
comment:16 by , 15 years ago
Cc: | added |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:17 by , 14 years ago
Patch needs improvement: | set |
---|
comment:18 by , 14 years ago
Cc: | added |
---|
comment:19 by , 14 years ago
milestone: | → 1.3 |
---|
by , 14 years ago
Attachment: | django-assert-num-queries.diff added |
---|
Implementation still using connection.queries, and application throughout the codebase.
by , 14 years ago
Attachment: | django-assert-num-queries.2.diff added |
---|
comment:20 by , 14 years ago
Owner: | changed from | to
---|---|
Status: | assigned → new |
by , 14 years ago
Attachment: | django-assert-num-queries.3.diff added |
---|
comment:21 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Malcolm suggests that this wait until after his queryset refactor as it'll be easier then.