diff --git a/CHANGELOG b/CHANGELOG index 87f46fff8..20a86f0f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,10 @@ 2.7.0.dev (compared to 2.6.4) ----------------------------- -- fix issue616: conftest.py files and their contained fixutres are now +- fix issue616: conftest.py files and their contained fixutres are now properly considered for visibility, independently from the exact current working directory and test arguments that are used. - Many thanks to Eric Siegerman and his PR235 which contains + Many thanks to Eric Siegerman and his PR235 which contains systematic tests for conftest visibility and now passes. This change also introduces the concept of a ``rootdir`` which is printed as a new pytest header and documented in the pytest @@ -12,7 +12,7 @@ - change reporting of "diverted" tests, i.e. tests that are collected in one file but actually come from another (e.g. when tests in a test class - come from a base class in a different file). We now show the nodeid + come from a base class in a different file). We now show the nodeid and indicate via a postfix the other file. - add ability to set command line options by environment variable PYTEST_ADDOPTS. @@ -24,7 +24,7 @@ - fix issue650: new option ``--docttest-ignore-import-errors`` which will turn import errors in doctests into skips. Thanks Charles Cloud for the complete PR. - + - fix issue655: work around different ways that cause python2/3 to leak sys.exc_info into fixtures/tests causing failures in 3rd party code @@ -55,6 +55,7 @@ - "python_classes" and "python_functions" options now support glob-patterns for test discovery, as discussed in issue600. Thanks Ldiary Translations. +- allow to override parametrized fixtures with non-parametrized ones and vice versa (bubenkoff). 2.6.4 ---------- diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..50772f4fd --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# create virtual environment +PYTHON = python2.7 + +.env: + virtualenv .env -p $(PYTHON) + +# install all needed for development +develop: .env + .env/bin/pip install -e .[test] tox + +# clean the development envrironment +clean: + -rm -rf .env diff --git a/_pytest/python.py b/_pytest/python.py index 183585302..06d8ec6e0 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1714,7 +1714,7 @@ class FixtureManager: faclist = metafunc._arg2fixturedefs.get(argname) if faclist is None: continue # will raise FixtureLookupError at setup time - for fixturedef in faclist: + for fixturedef in faclist[-1:]: if fixturedef.params is not None: metafunc.parametrize(argname, fixturedef.params, indirect=True, scope=fixturedef.scope, diff --git a/setup.py b/setup.py index 7a1cc281e..b643e7ca7 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,8 @@ classifiers = ['Development Status :: 6 - Mature', ('Programming Language :: Python :: %s' % x) for x in '2 2.6 2.7 3 3.2 3.3 3.4'.split()] -long_description = open('README.rst').read() +with open('README.rst') as fd: + long_description = fd.read() def main(): diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 07fd0abcb..00124a532 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -226,6 +226,114 @@ class TestFillFixtures: result = testdir.runpytest() assert result.ret == 0 + def test_override_parametrized_fixture_conftest_module(self, testdir): + """Test override of the parametrized fixture with non-parametrized one on the test module level.""" + testdir.makeconftest(""" + import pytest + + @pytest.fixture(params=[1, 2, 3]) + def spam(request): + return request.param + """) + testfile = testdir.makepyfile(""" + import pytest + + @pytest.fixture + def spam(): + return 'spam' + + def test_spam(spam): + assert spam == 'spam' + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*1 passed*"]) + result = testdir.runpytest(testfile) + result.stdout.fnmatch_lines(["*1 passed*"]) + + def test_override_parametrized_fixture_conftest_conftest(self, testdir): + """Test override of the parametrized fixture with non-parametrized one on the conftest level.""" + testdir.makeconftest(""" + import pytest + + @pytest.fixture(params=[1, 2, 3]) + def spam(request): + return request.param + """) + subdir = testdir.mkpydir('subdir') + subdir.join("conftest.py").write(py.code.Source(""" + import pytest + + @pytest.fixture + def spam(): + return 'spam' + """)) + testfile = subdir.join("test_spam.py") + testfile.write(py.code.Source(""" + def test_spam(spam): + assert spam == "spam" + """)) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*1 passed*"]) + result = testdir.runpytest(testfile) + result.stdout.fnmatch_lines(["*1 passed*"]) + + def test_override_non_parametrized_fixture_conftest_module(self, testdir): + """Test override of the non-parametrized fixture with parametrized one on the test module level.""" + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def spam(): + return 'spam' + """) + testfile = testdir.makepyfile(""" + import pytest + + @pytest.fixture(params=[1, 2, 3]) + def spam(request): + return request.param + + params = {'spam': 1} + + def test_spam(spam): + assert spam == params['spam'] + params['spam'] += 1 + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*3 passed*"]) + result = testdir.runpytest(testfile) + result.stdout.fnmatch_lines(["*3 passed*"]) + + def test_override_non_parametrized_fixture_conftest_conftest(self, testdir): + """Test override of the non-parametrized fixture with parametrized one on the conftest level.""" + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def spam(): + return 'spam' + """) + subdir = testdir.mkpydir('subdir') + subdir.join("conftest.py").write(py.code.Source(""" + import pytest + + @pytest.fixture(params=[1, 2, 3]) + def spam(request): + return request.param + """)) + testfile = subdir.join("test_spam.py") + testfile.write(py.code.Source(""" + params = {'spam': 1} + + def test_spam(spam): + assert spam == params['spam'] + params['spam'] += 1 + """)) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*3 passed*"]) + result = testdir.runpytest(testfile) + result.stdout.fnmatch_lines(["*3 passed*"]) + def test_autouse_fixture_plugin(self, testdir): # A fixture from a plugin has no baseid set, which screwed up # the autouse fixture handling.