diff --git a/CHANGELOG b/CHANGELOG index 08ebea21e..9fd20860f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,12 @@ -Changes between 2.3.4 and 2.3.5dev +Changes between 2.3.5 and DEV +----------------------------------- + +- (experimental) allow fixture functions to be + implemented as context managers + + + +Changes between 2.3.4 and 2.3.5 ----------------------------------- - never consider a fixture function for test function collection diff --git a/_pytest/__init__.py b/_pytest/__init__.py index b1e096143..9df86916d 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.6.dev1' +__version__ = '2.3.6.dev2' diff --git a/_pytest/python.py b/_pytest/python.py index b78e33513..529e0d688 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1613,6 +1613,29 @@ class FixtureManager: except ValueError: pass +def call_fixture_func(fixturefunc, request, kwargs): + if is_generator(fixturefunc): + iter = fixturefunc(**kwargs) + next = getattr(iter, "__next__", None) + if next is None: + next = getattr(iter, "next") + res = next() + def teardown(): + try: + next() + except StopIteration: + pass + else: + fs, lineno = getfslineno(fixturefunc) + location = "%s:%s" % (fs, lineno+1) + pytest.fail( + "fixture function %s has more than one 'yield': \n%s" % + (fixturefunc.__name__, location), pytrace=False) + request.addfinalizer(teardown) + else: + res = fixturefunc(**kwargs) + return res + class FixtureDef: """ A container for a factory definition. """ def __init__(self, fixturemanager, baseid, argname, func, scope, params, @@ -1663,7 +1686,7 @@ class FixtureDef: fixturefunc = fixturefunc.__get__(request.instance) except AttributeError: pass - result = fixturefunc(**kwargs) + result = call_fixture_func(fixturefunc, request, kwargs) assert not hasattr(self, "cached_result") self.cached_result = result return result diff --git a/setup.py b/setup.py index 8365b0626..1b4725108 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.3.6.dev1', + version='2.3.6.dev2', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 938555002..e82e38366 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1795,3 +1795,101 @@ class TestShowFixtures: *hello world* """) + + +class TestContextManagerFixtureFuncs: + def test_simple(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture + def arg1(): + print ("setup") + yield 1 + print ("teardown") + def test_1(arg1): + print ("test1 %s" % arg1) + def test_2(arg1): + print ("test2 %s" % arg1) + assert 0 + """) + result = testdir.runpytest("-s") + result.stdout.fnmatch_lines(""" + setup + test1 1 + teardown + setup + test2 1 + teardown + """) + + def test_scoped(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="module") + def arg1(): + print ("setup") + yield 1 + print ("teardown") + def test_1(arg1): + print ("test1 %s" % arg1) + def test_2(arg1): + print ("test2 %s" % arg1) + """) + result = testdir.runpytest("-s") + result.stdout.fnmatch_lines(""" + setup + test1 1 + test2 1 + teardown + """) + + def test_setup_exception(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="module") + def arg1(): + pytest.fail("setup") + yield 1 + def test_1(arg1): + pass + """) + result = testdir.runpytest("-s") + result.stdout.fnmatch_lines(""" + *pytest.fail*setup* + *1 error* + """) + + def test_teardown_exception(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="module") + def arg1(): + yield 1 + pytest.fail("teardown") + def test_1(arg1): + pass + """) + result = testdir.runpytest("-s") + result.stdout.fnmatch_lines(""" + *pytest.fail*teardown* + *1 passed*1 error* + """) + + + def test_yields_more_than_one(self, testdir): + testdir.makepyfile(""" + import pytest + @pytest.fixture(scope="module") + def arg1(): + yield 1 + yield 2 + def test_1(arg1): + pass + """) + result = testdir.runpytest("-s") + result.stdout.fnmatch_lines(""" + *fixture function* + *test_yields*:2* + """) + +