Merged in parametrized-fixture-override (pull request #257)
allow to override parametrized fixtures with non-parametrized ones and vice versa
This commit is contained in:
commit
eead0365b5
|
@ -1,10 +1,10 @@
|
||||||
2.7.0.dev (compared to 2.6.4)
|
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
|
properly considered for visibility, independently from the exact
|
||||||
current working directory and test arguments that are used.
|
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.
|
systematic tests for conftest visibility and now passes.
|
||||||
This change also introduces the concept of a ``rootdir`` which
|
This change also introduces the concept of a ``rootdir`` which
|
||||||
is printed as a new pytest header and documented in the pytest
|
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
|
- 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
|
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.
|
and indicate via a postfix the other file.
|
||||||
|
|
||||||
- add ability to set command line options by environment variable PYTEST_ADDOPTS.
|
- 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
|
- fix issue650: new option ``--docttest-ignore-import-errors`` which
|
||||||
will turn import errors in doctests into skips. Thanks Charles Cloud
|
will turn import errors in doctests into skips. Thanks Charles Cloud
|
||||||
for the complete PR.
|
for the complete PR.
|
||||||
|
|
||||||
- fix issue655: work around different ways that cause python2/3
|
- fix issue655: work around different ways that cause python2/3
|
||||||
to leak sys.exc_info into fixtures/tests causing failures in 3rd party code
|
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
|
- "python_classes" and "python_functions" options now support glob-patterns
|
||||||
for test discovery, as discussed in issue600. Thanks Ldiary Translations.
|
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
|
2.6.4
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -30,8 +30,8 @@ You can submit your plugin by subscribing to the `pytest-dev mail list
|
||||||
mail pointing to your existing pytest plugin repository which must have
|
mail pointing to your existing pytest plugin repository which must have
|
||||||
the following:
|
the following:
|
||||||
|
|
||||||
- PyPI presence with a ``setup.py`` that contains a license, ``pytest-``
|
- PyPI presence with a ``setup.py`` that contains a license, ``pytest-``
|
||||||
prefixed, version number, authors, short and long description.
|
prefixed, version number, authors, short and long description.
|
||||||
|
|
||||||
- a ``tox.ini`` for running tests using `tox <http://tox.testrun.org>`_.
|
- a ``tox.ini`` for running tests using `tox <http://tox.testrun.org>`_.
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ the following:
|
||||||
|
|
||||||
If no contributor strongly objects and two agree, the repo will be
|
If no contributor strongly objects and two agree, the repo will be
|
||||||
transferred to the ``pytest-dev`` organisation and you'll become a
|
transferred to the ``pytest-dev`` organisation and you'll become a
|
||||||
member of the ``pytest-dev`` team, with commit rights to all projects.
|
member of the ``pytest-dev`` team, with commit rights to all projects.
|
||||||
We recommend that each plugin has at least three people who have the
|
We recommend that each plugin has at least three people who have the
|
||||||
right to release to pypi.
|
right to release to pypi.
|
||||||
|
|
||||||
|
@ -128,22 +128,18 @@ Preparing Pull Requests on Bitbucket
|
||||||
The primary development platform for pytest is BitBucket. You can find all
|
The primary development platform for pytest is BitBucket. You can find all
|
||||||
the issues there and submit your pull requests.
|
the issues there and submit your pull requests.
|
||||||
|
|
||||||
1. Fork the
|
#. Fork the
|
||||||
`pytest BitBucket repository <https://bitbucket.org/pytest-dev/pytest>`__. It's
|
`pytest BitBucket repository <https://bitbucket.org/pytest-dev/pytest>`__. It's
|
||||||
fine to use ``pytest`` as your fork repository name because it will live
|
fine to use ``pytest`` as your fork repository name because it will live
|
||||||
under your user.
|
under your user.
|
||||||
|
|
||||||
.. _virtualenvactivate:
|
#. Create a development environment
|
||||||
|
(will implicitly use http://www.virtualenv.org/en/latest/)::
|
||||||
|
|
||||||
2. Create and activate a fork-specific virtualenv
|
$ make develop
|
||||||
(http://www.virtualenv.org/en/latest/)::
|
$ source .env/bin/activate
|
||||||
|
|
||||||
$ virtualenv pytest-venv
|
#. Clone your fork locally using `Mercurial <http://mercurial.selenic.com/>`_
|
||||||
$ source pytest-venv/bin/activate
|
|
||||||
|
|
||||||
.. _checkout:
|
|
||||||
|
|
||||||
3. Clone your fork locally using `Mercurial <http://mercurial.selenic.com/>`_
|
|
||||||
(``hg``) and create a branch::
|
(``hg``) and create a branch::
|
||||||
|
|
||||||
$ hg clone ssh://hg@bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest
|
$ hg clone ssh://hg@bitbucket.org/YOUR_BITBUCKET_USERNAME/pytest
|
||||||
|
@ -153,45 +149,46 @@ the issues there and submit your pull requests.
|
||||||
If you need some help with Mercurial, follow this quick start
|
If you need some help with Mercurial, follow this quick start
|
||||||
guide: http://mercurial.selenic.com/wiki/QuickStart
|
guide: http://mercurial.selenic.com/wiki/QuickStart
|
||||||
|
|
||||||
.. _testing-pytest:
|
#. Create a development environment
|
||||||
|
(will implicitly use http://www.virtualenv.org/en/latest/)::
|
||||||
|
|
||||||
4. You can now edit your local working copy. To test you need to
|
$ make develop
|
||||||
install the "tox" tool into your virtualenv::
|
$ source .env/bin/activate
|
||||||
|
|
||||||
$ pip install tox
|
#. You can now edit your local working copy.
|
||||||
|
|
||||||
You need to have Python 2.7 and 3.3 available in your system. Now
|
You need to have Python 2.7 and 3.4 available in your system. Now
|
||||||
running tests is as simple as issuing this command::
|
running tests is as simple as issuing this command::
|
||||||
|
|
||||||
$ python runtox.py -e py27,py33,flakes
|
$ python runtox.py -e py27,py34,flakes
|
||||||
|
|
||||||
This command will run tests via the "tox" tool against Python 2.7 and 3.3
|
This command will run tests via the "tox" tool against Python 2.7 and 3.4
|
||||||
and also perform "flakes" coding-style checks. ``runtox.py`` is
|
and also perform "flakes" coding-style checks. ``runtox.py`` is
|
||||||
a thin wrapper around ``tox`` which installs from a development package
|
a thin wrapper around ``tox`` which installs from a development package
|
||||||
index where newer (not yet released to pypi) versions of dependencies
|
index where newer (not yet released to pypi) versions of dependencies
|
||||||
(especially ``py``) might be present.
|
(especially ``py``) might be present.
|
||||||
|
|
||||||
To run tests on py27 and pass options (e.g. enter pdb on failure)
|
To run tests on py27 and pass options (e.g. enter pdb on failure)
|
||||||
to pytest you can do::
|
to pytest you can do::
|
||||||
|
|
||||||
$ python runtox.py -e py27 -- --pdb
|
$ python runtox.py -e py27 -- --pdb
|
||||||
|
|
||||||
or to only run tests in a particular test module on py33::
|
or to only run tests in a particular test module on py34::
|
||||||
|
|
||||||
$ python runtox.py -e py33 -- testing/test_config.py
|
$ python runtox.py -e py34 -- testing/test_config.py
|
||||||
|
|
||||||
5. Commit and push once your tests pass and you are happy with your change(s)::
|
#. Commit and push once your tests pass and you are happy with your change(s)::
|
||||||
|
|
||||||
$ hg commit -m"<commit message>"
|
$ hg commit -m"<commit message>"
|
||||||
$ hg push -b .
|
$ hg push -b .
|
||||||
|
|
||||||
6. Finally, submit a pull request through the BitBucket website:
|
#. Finally, submit a pull request through the BitBucket website:
|
||||||
|
|
||||||
.. image:: img/pullrequest.png
|
.. image:: img/pullrequest.png
|
||||||
:width: 700px
|
:width: 700px
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
source: YOUR_BITBUCKET_USERNAME/pytest
|
source: YOUR_BITBUCKET_USERNAME/pytest
|
||||||
branch: your-branch-name
|
branch: your-branch-name
|
||||||
|
@ -214,5 +211,3 @@ original repository. If you insist on using git with bitbucket/hg you
|
||||||
may try `gitifyhg <https://github.com/buchuki/gitifyhg>`_ but are on your
|
may try `gitifyhg <https://github.com/buchuki/gitifyhg>`_ but are on your
|
||||||
own and need to submit pull requests through the respective platform,
|
own and need to submit pull requests through the respective platform,
|
||||||
nevertheless.
|
nevertheless.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Set of targets useful for development/release process
|
||||||
|
PYTHON = python2.7
|
||||||
|
PATH := $(PWD)/.env/bin:$(PATH)
|
||||||
|
|
||||||
|
# prepare virtual python environment
|
||||||
|
.env:
|
||||||
|
virtualenv .env -p $(PYTHON)
|
||||||
|
|
||||||
|
# install all needed for development
|
||||||
|
develop: .env
|
||||||
|
pip install -e . tox -r requirements-docs.txt
|
||||||
|
|
||||||
|
# clean the development envrironment
|
||||||
|
clean:
|
||||||
|
-rm -rf .env
|
||||||
|
|
||||||
|
# generate documentation
|
||||||
|
docs: develop
|
||||||
|
find doc/en -name '*.txt' -not -path 'doc/en/_build/*' | xargs .env/bin/regendoc
|
||||||
|
cd doc/en; make html
|
||||||
|
|
||||||
|
# upload documentation
|
||||||
|
upload-docs: develop
|
||||||
|
find doc/en -name '*.txt' -not -path 'doc/en/_build/*' | xargs .env/bin/regendoc --update
|
||||||
|
cd doc/en; make install
|
|
@ -1712,13 +1712,17 @@ class FixtureManager:
|
||||||
def pytest_generate_tests(self, metafunc):
|
def pytest_generate_tests(self, metafunc):
|
||||||
for argname in metafunc.fixturenames:
|
for argname in metafunc.fixturenames:
|
||||||
faclist = metafunc._arg2fixturedefs.get(argname)
|
faclist = metafunc._arg2fixturedefs.get(argname)
|
||||||
if faclist is None:
|
if faclist:
|
||||||
continue # will raise FixtureLookupError at setup time
|
fixturedef = faclist[-1]
|
||||||
for fixturedef in faclist:
|
|
||||||
if fixturedef.params is not None:
|
if fixturedef.params is not None:
|
||||||
metafunc.parametrize(argname, fixturedef.params,
|
func_params = getattr(getattr(metafunc.function, 'parametrize', None), 'args', [[None]])
|
||||||
indirect=True, scope=fixturedef.scope,
|
# skip directly parametrized arguments
|
||||||
ids=fixturedef.ids)
|
if argname not in func_params and argname not in func_params[0]:
|
||||||
|
metafunc.parametrize(argname, fixturedef.params,
|
||||||
|
indirect=True, scope=fixturedef.scope,
|
||||||
|
ids=fixturedef.ids)
|
||||||
|
else:
|
||||||
|
continue # will raise FixtureLookupError at setup time
|
||||||
|
|
||||||
def pytest_collection_modifyitems(self, items):
|
def pytest_collection_modifyitems(self, items):
|
||||||
# separate parametrized setups
|
# separate parametrized setups
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
sphinx==1.2.3
|
||||||
|
hg+ssh://hg@bitbucket.org/RonnyPfannschmidt/regendoc#egg=regendoc
|
3
setup.py
3
setup.py
|
@ -13,7 +13,8 @@ classifiers = ['Development Status :: 6 - Mature',
|
||||||
('Programming Language :: Python :: %s' % x) for x in
|
('Programming Language :: Python :: %s' % x) for x in
|
||||||
'2 2.6 2.7 3 3.2 3.3 3.4'.split()]
|
'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():
|
def main():
|
||||||
|
|
|
@ -393,14 +393,31 @@ class TestFunction:
|
||||||
return 'value'
|
return 'value'
|
||||||
|
|
||||||
@pytest.mark.parametrize('value',
|
@pytest.mark.parametrize('value',
|
||||||
['overrided'])
|
['overridden'])
|
||||||
def test_overrided_via_param(value):
|
def test_overridden_via_param(value):
|
||||||
assert value == 'overrided'
|
assert value == 'overridden'
|
||||||
""")
|
""")
|
||||||
rec = testdir.inline_run()
|
rec = testdir.inline_run()
|
||||||
rec.assertoutcome(passed=1)
|
rec.assertoutcome(passed=1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parametrize_overrides_parametrized_fixture(self, testdir):
|
||||||
|
"""Test parametrization when parameter overrides existing parametrized fixture with same name."""
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(params=[1, 2])
|
||||||
|
def value(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value',
|
||||||
|
['overridden'])
|
||||||
|
def test_overridden_via_param(value):
|
||||||
|
assert value == 'overridden'
|
||||||
|
""")
|
||||||
|
rec = testdir.inline_run()
|
||||||
|
rec.assertoutcome(passed=1)
|
||||||
|
|
||||||
def test_parametrize_with_mark(selfself, testdir):
|
def test_parametrize_with_mark(selfself, testdir):
|
||||||
items = testdir.getitems("""
|
items = testdir.getitems("""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
|
@ -226,6 +226,114 @@ class TestFillFixtures:
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
assert result.ret == 0
|
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):
|
def test_autouse_fixture_plugin(self, testdir):
|
||||||
# A fixture from a plugin has no baseid set, which screwed up
|
# A fixture from a plugin has no baseid set, which screwed up
|
||||||
# the autouse fixture handling.
|
# the autouse fixture handling.
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -136,7 +136,7 @@ commands=
|
||||||
minversion=2.0
|
minversion=2.0
|
||||||
plugins=pytester
|
plugins=pytester
|
||||||
#--pyargs --doctest-modules --ignore=.tox
|
#--pyargs --doctest-modules --ignore=.tox
|
||||||
addopts= -rxsX
|
addopts= -rxsX -vl
|
||||||
rsyncdirs=tox.ini pytest.py _pytest testing
|
rsyncdirs=tox.ini pytest.py _pytest testing
|
||||||
python_files=test_*.py *_test.py testing/*/*.py
|
python_files=test_*.py *_test.py testing/*/*.py
|
||||||
python_classes=Test Acceptance
|
python_classes=Test Acceptance
|
||||||
|
|
Loading…
Reference in New Issue