Skip to content

Commit a67ab3b

Browse files
authored
unittest: help with setUpClass not being a classmethod (#544)
1 parent ba8f9d6 commit a67ab3b

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

pytest_django/plugin.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
CONFIGURATION_ENV = 'DJANGO_CONFIGURATION'
4343
INVALID_TEMPLATE_VARS_ENV = 'FAIL_INVALID_TEMPLATE_VARS'
4444

45+
PY2 = sys.version_info[0] == 2
46+
4547

4648
# ############### pytest hooks ################
4749

@@ -259,7 +261,7 @@ def pytest_configure():
259261
_setup_django()
260262

261263

262-
def _method_is_defined_at_leaf(cls, method_name):
264+
def _classmethod_is_defined_at_leaf(cls, method_name):
263265
super_method = None
264266

265267
for base_cls in cls.__bases__:
@@ -269,7 +271,15 @@ def _method_is_defined_at_leaf(cls, method_name):
269271
assert super_method is not None, (
270272
'%s could not be found in base class' % method_name)
271273

272-
return getattr(cls, method_name).__func__ is not super_method.__func__
274+
method = getattr(cls, method_name)
275+
276+
try:
277+
f = method.__func__
278+
except AttributeError:
279+
pytest.fail('%s.%s should be a classmethod' % (cls, method_name))
280+
if PY2 and not (inspect.ismethod(method) and method.__self__ is cls):
281+
pytest.fail('%s.%s should be a classmethod' % (cls, method_name))
282+
return f is not super_method.__func__
273283

274284

275285
_disabled_classmethods = {}
@@ -281,9 +291,9 @@ def _disable_class_methods(cls):
281291

282292
_disabled_classmethods[cls] = (
283293
cls.setUpClass,
284-
_method_is_defined_at_leaf(cls, 'setUpClass'),
294+
_classmethod_is_defined_at_leaf(cls, 'setUpClass'),
285295
cls.tearDownClass,
286-
_method_is_defined_at_leaf(cls, 'tearDownClass'),
296+
_classmethod_is_defined_at_leaf(cls, 'tearDownClass'),
287297
)
288298

289299
cls.setUpClass = types.MethodType(lambda cls: None, cls)

tests/test_unittest.py

+19
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,25 @@ def test_pass(self):
122122
])
123123
assert result.ret == 0
124124

125+
def test_setUpClass_not_being_a_classmethod(self, django_testdir):
126+
django_testdir.create_test_module('''
127+
from django.test import TestCase
128+
129+
class TestFoo(TestCase):
130+
def setUpClass(self):
131+
pass
132+
133+
def test_pass(self):
134+
pass
135+
''')
136+
137+
result = django_testdir.runpytest_subprocess('-v', '-s')
138+
result.stdout.fnmatch_lines([
139+
"* ERROR at setup of TestFoo.test_pass *",
140+
"E *Failed: <class 'tpkg.test_the_test.TestFoo'>.setUpClass should be a classmethod", # noqa:E501
141+
])
142+
assert result.ret == 1
143+
125144
def test_multi_inheritance_setUpClass(self, django_testdir):
126145
django_testdir.create_test_module('''
127146
from django.test import TestCase

0 commit comments

Comments
 (0)