Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8a8c7ee7f3
commit
1c3ddcd97a
|
|
@ -86,7 +86,14 @@ def assert_expected_query_count(test_case, name):
|
|||
Assert that the wrapped block performs the number of SQL queries recorded
|
||||
in the per-app baseline file (`<app>/tests/query_counts.json`).
|
||||
|
||||
The baseline key is `<model_name>:<name>`, derived from `test_case.model`.
|
||||
The baseline key is `<model_label>:<name>`. By default `<model_label>` is
|
||||
derived from `test_case.model._meta.model_name`. Test cases that use
|
||||
runtime-generated models with unstable names (e.g. names derived from a
|
||||
database primary-key sequence) can declare a ``query_count_model_label``
|
||||
class attribute to provide a stable, human-assigned label instead:
|
||||
|
||||
class MyViewTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
query_count_model_label = 'my-stable-label'
|
||||
|
||||
When the `UPDATE_QUERY_COUNTS` environment variable is set, the assertion
|
||||
is skipped and the observed count is written back to the baseline file
|
||||
|
|
@ -94,7 +101,8 @@ def assert_expected_query_count(test_case, name):
|
|||
"""
|
||||
model = test_case.model
|
||||
app_label = model._meta.app_label
|
||||
model_name = model._meta.model_name
|
||||
label = getattr(test_case, 'query_count_model_label', None)
|
||||
model_name = label if label is not None else model._meta.model_name
|
||||
key = f'{model_name}:{name}'
|
||||
|
||||
if _is_update_mode():
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
import os
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
import utilities.testing.query_counts as qc_mod
|
||||
from utilities.testing.query_counts import assert_expected_query_count
|
||||
|
||||
|
||||
class _FakeModel:
|
||||
"""Minimal stand-in for a Django model class with _meta."""
|
||||
|
||||
class _meta:
|
||||
app_label = 'utilities'
|
||||
model_name = 'fakemodel'
|
||||
|
||||
|
||||
class _BaseTestCase:
|
||||
"""Shared base for fake test-case objects passed to assert_expected_query_count."""
|
||||
model = _FakeModel
|
||||
|
||||
|
||||
class AssertExpectedQueryCountLabelTestCase(TestCase):
|
||||
"""
|
||||
Verify that assert_expected_query_count uses query_count_model_label when
|
||||
set on the test case and falls back to model._meta.model_name otherwise.
|
||||
"""
|
||||
|
||||
def _make_test_case(self, label_value=None, set_attr=False):
|
||||
"""Return a minimal fake test case object."""
|
||||
tc = type('FakeTestCase', (_BaseTestCase,), {'fail': self.fail})()
|
||||
if set_attr:
|
||||
tc.query_count_model_label = label_value
|
||||
return tc
|
||||
|
||||
def _recorded_key(self, test_case):
|
||||
"""
|
||||
Drive assert_expected_query_count in UPDATE mode and return the key it
|
||||
wrote. We patch _record_update to capture the key without touching the
|
||||
filesystem.
|
||||
"""
|
||||
captured = {}
|
||||
|
||||
original = qc_mod._record_update
|
||||
|
||||
def fake_record(app_label, key, count):
|
||||
captured['key'] = key
|
||||
|
||||
original_parallel = qc_mod._is_parallel_test_run
|
||||
qc_mod._record_update = fake_record
|
||||
qc_mod._is_parallel_test_run = lambda: False
|
||||
try:
|
||||
old_env = os.environ.get(qc_mod.UPDATE_ENV_VAR)
|
||||
os.environ[qc_mod.UPDATE_ENV_VAR] = '1'
|
||||
try:
|
||||
with assert_expected_query_count(test_case, 'test_name'):
|
||||
pass
|
||||
finally:
|
||||
if old_env is None:
|
||||
del os.environ[qc_mod.UPDATE_ENV_VAR]
|
||||
else:
|
||||
os.environ[qc_mod.UPDATE_ENV_VAR] = old_env
|
||||
finally:
|
||||
qc_mod._record_update = original
|
||||
qc_mod._is_parallel_test_run = original_parallel
|
||||
|
||||
return captured['key']
|
||||
|
||||
def test_default_uses_model_name(self):
|
||||
"""Without query_count_model_label the key prefix is model._meta.model_name."""
|
||||
tc = self._make_test_case()
|
||||
key = self._recorded_key(tc)
|
||||
self.assertEqual(key, 'fakemodel:test_name')
|
||||
|
||||
def test_custom_label_overrides_model_name(self):
|
||||
"""A set query_count_model_label is used as the key prefix."""
|
||||
tc = self._make_test_case(label_value='my-stable-label', set_attr=True)
|
||||
key = self._recorded_key(tc)
|
||||
self.assertEqual(key, 'my-stable-label:test_name')
|
||||
|
||||
def test_empty_string_label_is_used_as_prefix(self):
|
||||
"""An empty-string query_count_model_label is used as-is, not treated as falsy."""
|
||||
tc = self._make_test_case(label_value='', set_attr=True)
|
||||
key = self._recorded_key(tc)
|
||||
self.assertEqual(key, ':test_name')
|
||||
Loading…
Reference in New Issue