Skip to content

Commit 9b7f47b

Browse files
Martijn van Oosterhoutblueyed
Martijn van Oosterhout
authored andcommitted
Fix classmethod test
This test was incorrect in the case where the method was inherited from a subclass. Which ironically is precisely what the function was supposed to test. Additionally, there was a problem where the restored methods were bound to the wrong class. Added test case and fixed that also. Fixes #597
1 parent 8bd3d3e commit 9b7f47b

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
unreleased
5+
----------
6+
7+
* Fix test for classmethod with Django TestCases (#597, #598).
8+
49
3.2.1
510
-----
611

pytest_django/plugin.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,9 @@ def _classmethod_is_defined_at_leaf(cls, method_name):
277277
f = method.__func__
278278
except AttributeError:
279279
pytest.fail('%s.%s should be a classmethod' % (cls, method_name))
280-
if PY2 and not (inspect.ismethod(method) and method.__self__ is cls):
280+
if PY2 and not (inspect.ismethod(method) and
281+
inspect.isclass(method.__self__) and
282+
issubclass(cls, method.__self__)):
281283
pytest.fail('%s.%s should be a classmethod' % (cls, method_name))
282284
return f is not super_method.__func__
283285

@@ -290,9 +292,11 @@ def _disable_class_methods(cls):
290292
return
291293

292294
_disabled_classmethods[cls] = (
293-
cls.setUpClass,
295+
# Get the classmethod object (not the resulting bound method),
296+
# otherwise inheritence will be broken when restoring.
297+
cls.__dict__.get('setUpClass'),
294298
_classmethod_is_defined_at_leaf(cls, 'setUpClass'),
295-
cls.tearDownClass,
299+
cls.__dict__.get('tearDownClass'),
296300
_classmethod_is_defined_at_leaf(cls, 'tearDownClass'),
297301
)
298302

tests/test_unittest.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,79 @@ def test_pass(self):
141141
])
142142
assert result.ret == 1
143143

144+
def test_setUpClass_multiple_subclasses(self, django_testdir):
145+
django_testdir.create_test_module('''
146+
from django.test import TestCase
147+
148+
149+
class TestFoo(TestCase):
150+
@classmethod
151+
def setUpClass(cls):
152+
super(TestFoo, cls).setUpClass()
153+
154+
def test_shared(self):
155+
pass
156+
157+
158+
class TestBar(TestFoo):
159+
def test_bar1(self):
160+
pass
161+
162+
163+
class TestBar2(TestFoo):
164+
def test_bar21(self):
165+
pass
166+
''')
167+
168+
result = django_testdir.runpytest_subprocess('-v', '-s')
169+
result.stdout.fnmatch_lines([
170+
"*TestFoo::test_shared Creating test database for*",
171+
"PASSED",
172+
"*TestBar::test_bar1 PASSED",
173+
"*TestBar::test_shared PASSED",
174+
"*TestBar2::test_bar21 PASSED",
175+
"*TestBar2::test_shared PASSED*",
176+
])
177+
assert result.ret == 0
178+
179+
def test_setUpClass_skip(self, django_testdir):
180+
django_testdir.create_test_module('''
181+
from django.test import TestCase
182+
import pytest
183+
184+
185+
class TestFoo(TestCase):
186+
@classmethod
187+
def setUpClass(cls):
188+
if cls is TestFoo:
189+
raise pytest.skip("Skip base class")
190+
super(TestFoo, cls).setUpClass()
191+
192+
def test_shared(self):
193+
pass
194+
195+
196+
class TestBar(TestFoo):
197+
def test_bar1(self):
198+
pass
199+
200+
201+
class TestBar2(TestFoo):
202+
def test_bar21(self):
203+
pass
204+
''')
205+
206+
result = django_testdir.runpytest_subprocess('-v', '-s')
207+
result.stdout.fnmatch_lines([
208+
"*TestFoo::test_shared Creating test database for*",
209+
"SKIPPED",
210+
"*TestBar::test_bar1 PASSED",
211+
"*TestBar::test_shared PASSED",
212+
"*TestBar2::test_bar21 PASSED",
213+
"*TestBar2::test_shared PASSED*",
214+
])
215+
assert result.ret == 0
216+
144217
def test_multi_inheritance_setUpClass(self, django_testdir):
145218
django_testdir.create_test_module('''
146219
from django.test import TestCase

0 commit comments

Comments
 (0)