From e156e38ee7ecca3fbe192224b488080f4e8ddce9 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 24 Nov 2017 11:36:48 +0100 Subject: [PATCH 1/3] unittest: help with setUpClass not being a classmethod --- pytest_django/plugin.py | 7 ++++++- tests/test_unittest.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 7f85bcdc7..099f6570e 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -268,7 +268,12 @@ def _method_is_defined_at_leaf(cls, method_name): assert super_method is not None, ( '%s could not be found in base class' % method_name) - return getattr(cls, method_name).__func__ is not super_method.__func__ + method = getattr(cls, method_name) + try: + f = method.__func__ + except AttributeError: + pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) + return f is not super_method.__func__ _disabled_classmethods = {} diff --git a/tests/test_unittest.py b/tests/test_unittest.py index 954ff6d51..3d0906742 100644 --- a/tests/test_unittest.py +++ b/tests/test_unittest.py @@ -122,6 +122,25 @@ def test_pass(self): ]) assert result.ret == 0 + def test_setUpClass_not_being_a_classmethod(self, django_testdir): + django_testdir.create_test_module(''' + from django.test import TestCase + + class TestFoo(TestCase): + def setUpClass(self): + pass + + def test_pass(self): + pass + ''') + + result = django_testdir.runpytest_subprocess('-v', '-s') + result.stdout.fnmatch_lines([ + "tpkg/test_the_test.py::TestFoo::test_pass ERROR", + "E Failed: .setUpClass should be a classmethod", # noqa:E501 + ]) + assert result.ret == 1 + def test_multi_inheritance_setUpClass(self, django_testdir): django_testdir.create_test_module(''' from django.test import TestCase From ec4940e4e192fafde3f1aa0f57a6e8a67360299b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 24 Nov 2017 13:08:10 +0100 Subject: [PATCH 2/3] fixup! unittest: help with setUpClass not being a classmethod --- pytest_django/plugin.py | 7 ++++--- tests/test_unittest.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 099f6570e..292a960a8 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -270,10 +270,11 @@ def _method_is_defined_at_leaf(cls, method_name): method = getattr(cls, method_name) try: - f = method.__func__ + return method.__func__ is not super_method.__func__ except AttributeError: - pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) - return f is not super_method.__func__ + if not (inspect.ismethod(method) and method.__self__ is cls): + pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) + raise _disabled_classmethods = {} diff --git a/tests/test_unittest.py b/tests/test_unittest.py index 3d0906742..7b93b3771 100644 --- a/tests/test_unittest.py +++ b/tests/test_unittest.py @@ -136,8 +136,8 @@ def test_pass(self): result = django_testdir.runpytest_subprocess('-v', '-s') result.stdout.fnmatch_lines([ - "tpkg/test_the_test.py::TestFoo::test_pass ERROR", - "E Failed: .setUpClass should be a classmethod", # noqa:E501 + "* ERROR at setup of TestFoo.test_pass *", + "E *Failed: .setUpClass should be a classmethod", # noqa:E501 ]) assert result.ret == 1 From 70dfd863e5422988c6fd96ae4c52b2f96194dee9 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 24 Nov 2017 16:18:57 +0100 Subject: [PATCH 3/3] fixup! fixup! unittest: help with setUpClass not being a classmethod --- pytest_django/plugin.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 292a960a8..3100aa15e 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -41,6 +41,8 @@ CONFIGURATION_ENV = 'DJANGO_CONFIGURATION' INVALID_TEMPLATE_VARS_ENV = 'FAIL_INVALID_TEMPLATE_VARS' +PY2 = sys.version_info[0] == 2 + # ############### pytest hooks ################ @@ -258,7 +260,7 @@ def pytest_configure(): _setup_django() -def _method_is_defined_at_leaf(cls, method_name): +def _classmethod_is_defined_at_leaf(cls, method_name): super_method = None for base_cls in cls.__bases__: @@ -269,12 +271,14 @@ def _method_is_defined_at_leaf(cls, method_name): '%s could not be found in base class' % method_name) method = getattr(cls, method_name) + try: - return method.__func__ is not super_method.__func__ + f = method.__func__ except AttributeError: - if not (inspect.ismethod(method) and method.__self__ is cls): - pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) - raise + pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) + if PY2 and not (inspect.ismethod(method) and method.__self__ is cls): + pytest.fail('%s.%s should be a classmethod' % (cls, method_name)) + return f is not super_method.__func__ _disabled_classmethods = {} @@ -286,9 +290,9 @@ def _disable_class_methods(cls): _disabled_classmethods[cls] = ( cls.setUpClass, - _method_is_defined_at_leaf(cls, 'setUpClass'), + _classmethod_is_defined_at_leaf(cls, 'setUpClass'), cls.tearDownClass, - _method_is_defined_at_leaf(cls, 'tearDownClass'), + _classmethod_is_defined_at_leaf(cls, 'tearDownClass'), ) cls.setUpClass = types.MethodType(lambda cls: None, cls)