|
|
|
|
@@ -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::
|
|
|
|
|
|
|
|
|
|
|