Update docs in prol of using yield statements
This commit is contained in:
parent
98acda426f
commit
fe4f23c1bf
|
@ -4,8 +4,8 @@ import pytest
|
|||
@pytest.fixture("session")
|
||||
def setup(request):
|
||||
setup = CostlySetup()
|
||||
request.addfinalizer(setup.finalize)
|
||||
return setup
|
||||
yield setup
|
||||
setup.finalize()
|
||||
|
||||
class CostlySetup:
|
||||
def __init__(self):
|
||||
|
|
|
@ -648,15 +648,14 @@ here is a little example implemented via a local plugin::
|
|||
|
||||
@pytest.fixture
|
||||
def something(request):
|
||||
def fin():
|
||||
# request.node is an "item" because we use the default
|
||||
# "function" scope
|
||||
if request.node.rep_setup.failed:
|
||||
print ("setting up a test failed!", request.node.nodeid)
|
||||
elif request.node.rep_setup.passed:
|
||||
if request.node.rep_call.failed:
|
||||
print ("executing test failed", request.node.nodeid)
|
||||
request.addfinalizer(fin)
|
||||
yield
|
||||
# request.node is an "item" because we use the default
|
||||
# "function" scope
|
||||
if request.node.rep_setup.failed:
|
||||
print ("setting up a test failed!", request.node.nodeid)
|
||||
elif request.node.rep_setup.passed:
|
||||
if request.node.rep_call.failed:
|
||||
print ("executing test failed", request.node.nodeid)
|
||||
|
||||
|
||||
if you then have failing tests::
|
||||
|
|
|
@ -34,11 +34,6 @@ both styles, moving incrementally from classic to new style, as you
|
|||
prefer. You can also start out from existing :ref:`unittest.TestCase
|
||||
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
|
||||
|
||||
.. note::
|
||||
|
||||
pytest-2.4 introduced an additional :ref:`yield fixture mechanism
|
||||
<yieldfixture>` for easier context manager integration and more linear
|
||||
writing of teardown code.
|
||||
|
||||
.. _`funcargs`:
|
||||
.. _`funcarg mechanism`:
|
||||
|
@ -247,9 +242,8 @@ Fixture finalization / executing teardown code
|
|||
-------------------------------------------------------------
|
||||
|
||||
pytest supports execution of fixture specific finalization code
|
||||
when the fixture goes out of scope. By accepting a ``request`` object
|
||||
into your fixture function you can call its ``request.addfinalizer`` one
|
||||
or multiple times::
|
||||
when the fixture goes out of scope. By using a ``yield`` statement instead of ``return``, all
|
||||
the code after the *yield* statement serves as the teardown code.::
|
||||
|
||||
# content of conftest.py
|
||||
|
||||
|
@ -259,14 +253,12 @@ or multiple times::
|
|||
@pytest.fixture(scope="module")
|
||||
def smtp(request):
|
||||
smtp = smtplib.SMTP("smtp.gmail.com")
|
||||
def fin():
|
||||
print ("teardown smtp")
|
||||
smtp.close()
|
||||
request.addfinalizer(fin)
|
||||
return smtp # provide the fixture value
|
||||
yield smtp # provide the fixture value
|
||||
print("teardown smtp")
|
||||
smtp.close()
|
||||
|
||||
The ``fin`` function will execute when the last test using
|
||||
the fixture in the module has finished execution.
|
||||
The ``print`` and ``smtp.close()`` statements will execute when the last test using
|
||||
the fixture in the module has finished execution, regardless of the exception status of the tests.
|
||||
|
||||
Let's execute it::
|
||||
|
||||
|
@ -282,14 +274,55 @@ occur around each single test. In either case the test
|
|||
module itself does not need to change or know about these details
|
||||
of fixture setup.
|
||||
|
||||
Note that we can also seamlessly use the ``yield`` syntax with ``with`` statements::
|
||||
|
||||
Finalization/teardown with yield fixtures
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
# content of test_yield2.py
|
||||
|
||||
Another alternative to the *request.addfinalizer()* method is to use *yield
|
||||
fixtures*. All the code after the *yield* statement serves as the teardown
|
||||
code. See the :ref:`yield fixture documentation <yieldfixture>`.
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def passwd():
|
||||
with open("/etc/passwd") as f:
|
||||
yield f.readlines()
|
||||
|
||||
def test_has_lines(passwd):
|
||||
assert len(passwd) >= 1
|
||||
|
||||
The file ``f`` will be closed after the test finished execution
|
||||
because the Python ``file`` object supports finalization when
|
||||
the ``with`` statement ends.
|
||||
|
||||
|
||||
.. note::
|
||||
Prior to version 2.10, in order to use a ``yield`` statement to execute teardown code one
|
||||
had to mark a fixture using the ``yield_fixture`` marker. From 2.10 onward, normal
|
||||
fixtures can use ``yield`` directly so the ``yield_fixture`` decorator is no longer needed
|
||||
and considered deprecated.
|
||||
|
||||
.. note::
|
||||
As historical note, another way to write teardown code is
|
||||
by accepting a ``request`` object into your fixture function and can call its
|
||||
``request.addfinalizer`` one or multiple times::
|
||||
|
||||
# content of conftest.py
|
||||
|
||||
import smtplib
|
||||
import pytest
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def smtp(request):
|
||||
smtp = smtplib.SMTP("smtp.gmail.com")
|
||||
def fin():
|
||||
print ("teardown smtp")
|
||||
smtp.close()
|
||||
request.addfinalizer(fin)
|
||||
return smtp # provide the fixture value
|
||||
|
||||
The ``fin`` function will execute when the last test using
|
||||
the fixture in the module has finished execution.
|
||||
|
||||
This method is still fully supported, but ``yield`` is recommended from 2.10 onward because
|
||||
it is considered simpler and better describes the natural code flow.
|
||||
|
||||
.. _`request-context`:
|
||||
|
||||
|
@ -309,12 +342,9 @@ read an optional server URL from the test module which uses our fixture::
|
|||
def smtp(request):
|
||||
server = getattr(request.module, "smtpserver", "smtp.gmail.com")
|
||||
smtp = smtplib.SMTP(server)
|
||||
|
||||
def fin():
|
||||
print ("finalizing %s (%s)" % (smtp, server))
|
||||
smtp.close()
|
||||
request.addfinalizer(fin)
|
||||
return smtp
|
||||
yield smtp
|
||||
print ("finalizing %s (%s)" % (smtp, server))
|
||||
smtp.close()
|
||||
|
||||
We use the ``request.module`` attribute to optionally obtain an
|
||||
``smtpserver`` attribute from the test module. If we just execute
|
||||
|
@ -351,7 +381,7 @@ from the module namespace.
|
|||
|
||||
.. _`fixture-parametrize`:
|
||||
|
||||
Parametrizing a fixture
|
||||
Parametrizing fixtures
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Fixture functions can be parametrized in which case they will be called
|
||||
|
@ -374,11 +404,9 @@ through the special :py:class:`request <FixtureRequest>` object::
|
|||
params=["smtp.gmail.com", "mail.python.org"])
|
||||
def smtp(request):
|
||||
smtp = smtplib.SMTP(request.param)
|
||||
def fin():
|
||||
print ("finalizing %s" % smtp)
|
||||
smtp.close()
|
||||
request.addfinalizer(fin)
|
||||
return smtp
|
||||
yield smtp
|
||||
print ("finalizing %s" % smtp)
|
||||
smtp.close()
|
||||
|
||||
The main change is the declaration of ``params`` with
|
||||
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
|
||||
|
@ -586,19 +614,15 @@ to show the setup/teardown flow::
|
|||
def modarg(request):
|
||||
param = request.param
|
||||
print (" SETUP modarg %s" % param)
|
||||
def fin():
|
||||
print (" TEARDOWN modarg %s" % param)
|
||||
request.addfinalizer(fin)
|
||||
return param
|
||||
yield param
|
||||
print (" TEARDOWN modarg %s" % param)
|
||||
|
||||
@pytest.fixture(scope="function", params=[1,2])
|
||||
def otherarg(request):
|
||||
param = request.param
|
||||
print (" SETUP otherarg %s" % param)
|
||||
def fin():
|
||||
print (" TEARDOWN otherarg %s" % param)
|
||||
request.addfinalizer(fin)
|
||||
return param
|
||||
yield param
|
||||
print (" TEARDOWN otherarg %s" % param)
|
||||
|
||||
def test_0(otherarg):
|
||||
print (" RUN test0 with otherarg %s" % otherarg)
|
||||
|
@ -777,7 +801,8 @@ self-contained implementation of this idea::
|
|||
@pytest.fixture(autouse=True)
|
||||
def transact(self, request, db):
|
||||
db.begin(request.function.__name__)
|
||||
request.addfinalizer(db.rollback)
|
||||
yield
|
||||
db.rollback()
|
||||
|
||||
def test_method1(self, db):
|
||||
assert db.intransaction == ["test_method1"]
|
||||
|
@ -817,10 +842,11 @@ active. The canonical way to do that is to put the transact definition
|
|||
into a conftest.py file **without** using ``autouse``::
|
||||
|
||||
# content of conftest.py
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def transact(self, request, db):
|
||||
db.begin()
|
||||
request.addfinalizer(db.rollback)
|
||||
yield
|
||||
db.rollback()
|
||||
|
||||
and then e.g. have a TestClass using it by declaring the need::
|
||||
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
Fixture functions using "yield" / context manager integration
|
||||
---------------------------------------------------------------
|
||||
|
||||
.. deprecated:: 2.10
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
.. important::
|
||||
Since pytest-2.10, fixtures using the normal ``fixture`` decorator can use a ``yield``
|
||||
statement to provide fixture values and execute teardown code, exactly like ``yield_fixture``
|
||||
described in this session.
|
||||
|
||||
.. regendoc:wipe
|
||||
|
||||
pytest-2.4 allows fixture functions to seamlessly use a ``yield`` instead
|
||||
|
|
Loading…
Reference in New Issue