document fixture override techniques
--HG-- branch : parametrized-fixture-override
This commit is contained in:
parent
c4623939af
commit
d1005ebb8f
|
@ -78,20 +78,20 @@ marked ``smtp`` fixture function. Running the test looks like this::
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4
|
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4
|
||||||
collected 1 items
|
collected 1 items
|
||||||
|
|
||||||
test_smtpsimple.py F
|
test_smtpsimple.py F
|
||||||
|
|
||||||
================================= FAILURES =================================
|
================================= FAILURES =================================
|
||||||
________________________________ test_ehlo _________________________________
|
________________________________ test_ehlo _________________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b88f2d1b0b8>
|
smtp = <smtplib.SMTP object at 0x2b88f2d1b0b8>
|
||||||
|
|
||||||
def test_ehlo(smtp):
|
def test_ehlo(smtp):
|
||||||
response, msg = smtp.ehlo()
|
response, msg = smtp.ehlo()
|
||||||
assert response == 250
|
assert response == 250
|
||||||
> assert "merlinux" in msg
|
> assert "merlinux" in msg
|
||||||
E TypeError: Type str doesn't support the buffer API
|
E TypeError: Type str doesn't support the buffer API
|
||||||
|
|
||||||
test_smtpsimple.py:11: TypeError
|
test_smtpsimple.py:11: TypeError
|
||||||
========================= 1 failed in 0.28 seconds =========================
|
========================= 1 failed in 0.28 seconds =========================
|
||||||
|
|
||||||
|
@ -195,31 +195,31 @@ inspect what is going on and can now run the tests::
|
||||||
=========================== test session starts ============================
|
=========================== test session starts ============================
|
||||||
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4
|
platform linux -- Python 3.4.0 -- py-1.4.26 -- pytest-2.6.4
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
test_module.py FF
|
test_module.py FF
|
||||||
|
|
||||||
================================= FAILURES =================================
|
================================= FAILURES =================================
|
||||||
________________________________ test_ehlo _________________________________
|
________________________________ test_ehlo _________________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b29b71bd8d0>
|
smtp = <smtplib.SMTP object at 0x2b29b71bd8d0>
|
||||||
|
|
||||||
def test_ehlo(smtp):
|
def test_ehlo(smtp):
|
||||||
response = smtp.ehlo()
|
response = smtp.ehlo()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert "merlinux" in response[1]
|
> assert "merlinux" in response[1]
|
||||||
E TypeError: Type str doesn't support the buffer API
|
E TypeError: Type str doesn't support the buffer API
|
||||||
|
|
||||||
test_module.py:5: TypeError
|
test_module.py:5: TypeError
|
||||||
________________________________ test_noop _________________________________
|
________________________________ test_noop _________________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b29b71bd8d0>
|
smtp = <smtplib.SMTP object at 0x2b29b71bd8d0>
|
||||||
|
|
||||||
def test_noop(smtp):
|
def test_noop(smtp):
|
||||||
response = smtp.noop()
|
response = smtp.noop()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert 0 # for demo purposes
|
> assert 0 # for demo purposes
|
||||||
E assert 0
|
E assert 0
|
||||||
|
|
||||||
test_module.py:11: AssertionError
|
test_module.py:11: AssertionError
|
||||||
========================= 2 failed in 0.28 seconds =========================
|
========================= 2 failed in 0.28 seconds =========================
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ Let's execute it::
|
||||||
|
|
||||||
$ py.test -s -q --tb=no
|
$ py.test -s -q --tb=no
|
||||||
FFteardown smtp
|
FFteardown smtp
|
||||||
|
|
||||||
2 failed in 0.21 seconds
|
2 failed in 0.21 seconds
|
||||||
|
|
||||||
We see that the ``smtp`` instance is finalized after the two
|
We see that the ``smtp`` instance is finalized after the two
|
||||||
|
@ -377,50 +377,50 @@ So let's just do another run::
|
||||||
FFFF
|
FFFF
|
||||||
================================= FAILURES =================================
|
================================= FAILURES =================================
|
||||||
__________________________ test_ehlo[merlinux.eu] __________________________
|
__________________________ test_ehlo[merlinux.eu] __________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b6b796568d0>
|
smtp = <smtplib.SMTP object at 0x2b6b796568d0>
|
||||||
|
|
||||||
def test_ehlo(smtp):
|
def test_ehlo(smtp):
|
||||||
response = smtp.ehlo()
|
response = smtp.ehlo()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert "merlinux" in response[1]
|
> assert "merlinux" in response[1]
|
||||||
E TypeError: Type str doesn't support the buffer API
|
E TypeError: Type str doesn't support the buffer API
|
||||||
|
|
||||||
test_module.py:5: TypeError
|
test_module.py:5: TypeError
|
||||||
__________________________ test_noop[merlinux.eu] __________________________
|
__________________________ test_noop[merlinux.eu] __________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b6b796568d0>
|
smtp = <smtplib.SMTP object at 0x2b6b796568d0>
|
||||||
|
|
||||||
def test_noop(smtp):
|
def test_noop(smtp):
|
||||||
response = smtp.noop()
|
response = smtp.noop()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert 0 # for demo purposes
|
> assert 0 # for demo purposes
|
||||||
E assert 0
|
E assert 0
|
||||||
|
|
||||||
test_module.py:11: AssertionError
|
test_module.py:11: AssertionError
|
||||||
________________________ test_ehlo[mail.python.org] ________________________
|
________________________ test_ehlo[mail.python.org] ________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b6b79656780>
|
smtp = <smtplib.SMTP object at 0x2b6b79656780>
|
||||||
|
|
||||||
def test_ehlo(smtp):
|
def test_ehlo(smtp):
|
||||||
response = smtp.ehlo()
|
response = smtp.ehlo()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert "merlinux" in response[1]
|
> assert "merlinux" in response[1]
|
||||||
E TypeError: Type str doesn't support the buffer API
|
E TypeError: Type str doesn't support the buffer API
|
||||||
|
|
||||||
test_module.py:5: TypeError
|
test_module.py:5: TypeError
|
||||||
-------------------------- Captured stdout setup ---------------------------
|
-------------------------- Captured stdout setup ---------------------------
|
||||||
finalizing <smtplib.SMTP object at 0x2b6b796568d0>
|
finalizing <smtplib.SMTP object at 0x2b6b796568d0>
|
||||||
________________________ test_noop[mail.python.org] ________________________
|
________________________ test_noop[mail.python.org] ________________________
|
||||||
|
|
||||||
smtp = <smtplib.SMTP object at 0x2b6b79656780>
|
smtp = <smtplib.SMTP object at 0x2b6b79656780>
|
||||||
|
|
||||||
def test_noop(smtp):
|
def test_noop(smtp):
|
||||||
response = smtp.noop()
|
response = smtp.noop()
|
||||||
assert response[0] == 250
|
assert response[0] == 250
|
||||||
> assert 0 # for demo purposes
|
> assert 0 # for demo purposes
|
||||||
E assert 0
|
E assert 0
|
||||||
|
|
||||||
test_module.py:11: AssertionError
|
test_module.py:11: AssertionError
|
||||||
4 failed in 7.02 seconds
|
4 failed in 7.02 seconds
|
||||||
|
|
||||||
|
@ -519,10 +519,10 @@ Here we declare an ``app`` fixture which receives the previously defined
|
||||||
=========================== test session starts ============================
|
=========================== 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
|
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
|
collecting ... collected 2 items
|
||||||
|
|
||||||
test_appsetup.py::test_smtp_exists[merlinux.eu] PASSED
|
test_appsetup.py::test_smtp_exists[merlinux.eu] PASSED
|
||||||
test_appsetup.py::test_smtp_exists[mail.python.org] PASSED
|
test_appsetup.py::test_smtp_exists[mail.python.org] PASSED
|
||||||
|
|
||||||
========================= 2 passed in 6.63 seconds =========================
|
========================= 2 passed in 6.63 seconds =========================
|
||||||
|
|
||||||
Due to the parametrization of ``smtp`` the test will run twice with two
|
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 ============================
|
=========================== 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
|
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
|
collecting ... collected 8 items
|
||||||
|
|
||||||
test_module.py::test_0[1] test0 1
|
test_module.py::test_0[1] test0 1
|
||||||
PASSED
|
PASSED
|
||||||
test_module.py::test_0[2] test0 2
|
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
|
PASSED
|
||||||
test_module.py::test_2[2-mod2] test2 2 mod2
|
test_module.py::test_2[2-mod2] test2 2 mod2
|
||||||
PASSED
|
PASSED
|
||||||
|
|
||||||
========================= 8 passed in 0.01 seconds =========================
|
========================= 8 passed in 0.01 seconds =========================
|
||||||
|
|
||||||
You can see that the parametrized module-scoped ``modarg`` resource caused
|
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
|
fixtures functions starts at test classes, then test modules, then
|
||||||
``conftest.py`` files and finally builtin and third party plugins.
|
``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.
|
||||||
|
|
Loading…
Reference in New Issue