document fixture override techniques

--HG--
branch : parametrized-fixture-override
This commit is contained in:
Anatoly Bubenkov 2015-03-01 18:54:24 +01:00
parent c4623939af
commit d1005ebb8f
1 changed files with 208 additions and 30 deletions

View File

@ -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 = <smtplib.SMTP object at 0x2b88f2d1b0b8>
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 = <smtplib.SMTP object at 0x2b29b71bd8d0>
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 = <smtplib.SMTP object at 0x2b29b71bd8d0>
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 = <smtplib.SMTP object at 0x2b6b796568d0>
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 = <smtplib.SMTP object at 0x2b6b796568d0>
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 = <smtplib.SMTP object at 0x2b6b79656780>
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 <smtplib.SMTP object at 0x2b6b796568d0>
________________________ test_noop[mail.python.org] ________________________
smtp = <smtplib.SMTP object at 0x2b6b79656780>
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 <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.