diff --git a/CHANGELOG b/CHANGELOG index 03c804514..d0571f095 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,10 @@ - preserve warning functions after call to pytest.deprecated_call. Thanks Pieter Mulder for PR. +- fix issue854: autouse yield_fixtures defined as class members of + unittest.TestCase subclasses now work as expected. + Thannks xmo-odoo for the report and Bruno Oliveira for the PR. + - fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the fixtures declared on the first one. Thanks Florian Bruhin for reporting and Bruno Oliveira for the PR. diff --git a/_pytest/python.py b/_pytest/python.py index 76a6c4ed4..90bd8b99b 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1900,10 +1900,13 @@ class FixtureDef: self.finish() assert not hasattr(self, "cached_result") + fixturefunc = self.func + if self.unittest: - result = self.func(request.instance, **kwargs) + if request.instance is not None: + # bind the unbound method to the TestCase instance + fixturefunc = self.func.__get__(request.instance) else: - fixturefunc = self.func # the fixture function needs to be bound to the actual # request.instance so that code working with "self" behaves # as expected. @@ -1911,12 +1914,13 @@ class FixtureDef: fixturefunc = getimfunc(self.func) if fixturefunc != self.func: fixturefunc = fixturefunc.__get__(request.instance) - try: - result = call_fixture_func(fixturefunc, request, kwargs, - self.yieldctx) - except Exception: - self.cached_result = (None, my_cache_key, sys.exc_info()) - raise + + try: + result = call_fixture_func(fixturefunc, request, kwargs, + self.yieldctx) + except Exception: + self.cached_result = (None, my_cache_key, sys.exc_info()) + raise self.cached_result = (result, my_cache_key, None) return result diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 1ab016a5a..9e3962aad 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -607,18 +607,23 @@ def test_unittest_unexpected_failure(testdir): ]) - -def test_unittest_setup_interaction(testdir): +@pytest.mark.parametrize('fix_type, stmt', [ + ('fixture', 'return'), + ('yield_fixture', 'yield'), +]) +def test_unittest_setup_interaction(testdir, fix_type, stmt): testdir.makepyfile(""" import unittest import pytest class MyTestCase(unittest.TestCase): - @pytest.fixture(scope="class", autouse=True) + @pytest.{fix_type}(scope="class", autouse=True) def perclass(self, request): request.cls.hello = "world" - @pytest.fixture(scope="function", autouse=True) + {stmt} + @pytest.{fix_type}(scope="function", autouse=True) def perfunction(self, request): request.instance.funcname = request.function.__name__ + {stmt} def test_method1(self): assert self.funcname == "test_method1" @@ -629,7 +634,7 @@ def test_unittest_setup_interaction(testdir): def test_classattr(self): assert self.__class__.hello == "world" - """) + """.format(fix_type=fix_type, stmt=stmt)) result = testdir.runpytest() result.stdout.fnmatch_lines("*3 passed*")