diff --git a/doc/en/fixture.txt b/doc/en/fixture.txt index 0de85a7c7..f2982dc9a 100644 --- a/doc/en/fixture.txt +++ b/doc/en/fixture.txt @@ -78,20 +78,20 @@ marked ``smtp`` fixture function. Running the test looks like this:: =========================== test session starts ============================ platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4 collected 1 items - + test_smtpsimple.py F - + ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - + smtp = - + def test_ehlo(smtp): response, msg = smtp.ehlo() assert response == 250 > assert "merlinux" in msg E TypeError: Type str doesn't support the buffer API - + test_smtpsimple.py:11: TypeError ========================= 1 failed in 0.28 seconds ========================= @@ -195,31 +195,31 @@ inspect what is going on and can now run the tests:: =========================== test session starts ============================ platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4 collected 2 items - + test_module.py FF - + ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - + smtp = - + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 > assert "merlinux" in response[1] E TypeError: Type str doesn't support the buffer API - + test_module.py:5: TypeError ________________________________ test_noop _________________________________ - + smtp = - + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError ========================= 2 failed in 0.28 seconds ========================= @@ -268,7 +268,7 @@ Let's execute it:: $ py.test -s -q --tb=no FFteardown smtp - + 2 failed in 0.21 seconds We see that the ``smtp`` instance is finalized after the two @@ -377,50 +377,50 @@ So let's just do another run:: FFFF ================================= FAILURES ================================= __________________________ test_ehlo[merlinux.eu] __________________________ - + smtp = - + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 > assert "merlinux" in response[1] E TypeError: Type str doesn't support the buffer API - + test_module.py:5: TypeError __________________________ test_noop[merlinux.eu] __________________________ - + smtp = - + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError ________________________ test_ehlo[mail.python.org] ________________________ - + smtp = - + def test_ehlo(smtp): response = smtp.ehlo() assert response[0] == 250 > assert "merlinux" in response[1] E TypeError: Type str doesn't support the buffer API - + test_module.py:5: TypeError -------------------------- Captured stdout setup --------------------------- finalizing ________________________ test_noop[mail.python.org] ________________________ - + smtp = - + def test_noop(smtp): response = smtp.noop() assert response[0] == 250 > assert 0 # for demo purposes E assert 0 - + test_module.py:11: AssertionError 4 failed in 7.02 seconds @@ -519,10 +519,10 @@ Here we declare an ``app`` fixture which receives the previously defined =========================== test session starts ============================ platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4 collecting ... collected 2 items - + test_appsetup.py::test_smtp_exists[merlinux.eu] PASSED test_appsetup.py::test_smtp_exists[mail.python.org] PASSED - + ========================= 2 passed in 6.63 seconds ========================= Due to the parametrization of ``smtp`` the test will run twice with two @@ -583,7 +583,7 @@ Let's run the tests in verbose mode and with looking at the print-output:: =========================== test session starts ============================ platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4 collecting ... collected 8 items - + test_module.py::test_0[1] test0 1 PASSED test_module.py::test_0[2] test0 2 @@ -602,7 +602,7 @@ Let's run the tests in verbose mode and with looking at the print-output:: PASSED test_module.py::test_2[2-mod2] test2 2 mod2 PASSED - + ========================= 8 passed in 0.01 seconds ========================= You can see that the parametrized module-scoped ``modarg`` resource caused @@ -780,4 +780,182 @@ to a :ref:`conftest.py ` file or even separately installable fixtures functions starts at test classes, then test modules, then ``conftest.py`` files and finally builtin and third party plugins. +Overriding fixtures on various levels +------------------------------------- +In relatively large test suite, you most likely need to ``override`` a ``global`` or ``root`` fixture with a ``locally`` +defined one, keeping the test code readable and maintainable. + +Override a fixture on a folder (conftest) level +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Given the tests file structure is: + +:: + + tests/ + __init__.py + + conftest.py + # content of tests/conftest.py + import pytest + + @pytest.fixture + def username(): + return 'username' + + test_something.py + # content of tests/test_something.py + def test_username(username): + assert username == 'username' + + subfolder/ + __init__.py + + conftest.py + # content of tests/subfolder/conftest.py + import pytest + + @pytest.fixture + def username(username): + return 'overridden-' + username + + test_something.py + # content of tests/subfolder/test_something.py + def test_username(username): + assert username == 'overridden-username' + +As you can see, a fixture with the same name can be overridden for certain test folder level. +Note that the ``base`` or ``super`` fixture can be accessed from the ``overriding`` +fixture easily - used in the example above. + +Override a fixture on a test module level +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Given the tests file structure is: + +:: + + tests/ + __init__.py + + conftest.py + # content of tests/conftest.py + @pytest.fixture + def username(): + return 'username' + + test_something.py + # content of tests/test_something.py + import pytest + + @pytest.fixture + def username(username): + return 'overridden-' + username + + def test_username(username): + assert username == 'overridden-username' + + test_something_else.py + # content of tests/test_something_else.py + import pytest + + @pytest.fixture + def username(username): + return 'overridden-else-' + username + + def test_username(username): + assert username == 'overridden-else-username' + +In the example above, a fixture with the same name can be overridden for certain test module. + + +Override a fixture with direct test parametrization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Given the tests file structure is: + +:: + + tests/ + __init__.py + + conftest.py + # content of tests/conftest.py + import pytest + + @pytest.fixture + def username(): + return 'username' + + @pytest.fixture + def other_username(username): + return 'other-' + username + + test_something.py + # content of tests/test_something.py + import pytest + + @pytest.mark.parametrize('username', ['directly-overridden-username']) + def test_username(username): + assert username == 'directly-overridden-username' + + @pytest.mark.parametrize('username', ['directly-overridden-username-other']) + def test_username_other(other_username): + assert username == 'other-directly-overridden-username-other' + +In the example above, a fixture value is overridden by the test parameter value. Note that the value of the fixture +can be overridden this way even if the test doesn't use it directly (doesn't mention it in the function prototype). + + +Override a parametrized fixture with non-parametrized one and vice versa +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Given the tests file structure is: + +:: + + tests/ + __init__.py + + conftest.py + # content of tests/conftest.py + import pytest + + @pytest.fixture(params=['one', 'two', 'three']) + def parametrized_username(request): + return request.param + + @pytest.fixture + def non_parametrized_username(request): + return 'username' + + test_something.py + # content of tests/test_something.py + import pytest + + @pytest.fixture + def parametrized_username(): + return 'overridden-username' + + @pytest.fixture(params=['one', 'two', 'three']) + def non_parametrized_username(request): + return request.param + + def test_username(parametrized_username): + assert parametrized_username == 'overridden-username' + + def test_parametrized_username(non_parametrized_username): + assert non_parametrized_username in ['one', 'two', 'three'] + + test_something_else.py + # content of tests/test_something_else.py + def test_username(parametrized_username): + assert parametrized_username in ['one', 'two', 'three'] + + def test_username(non_parametrized_username): + assert non_parametrized_username == 'username' + +In the example above, a parametrized fixture is overridden with a non-parametrized version, and +a non-parametrized fixture is overridden with a parametrized version for certain test module. +The same applies for the test folder level obviously.