Source

pytest / doc / en / setup.txt

Full commit
.. _xunitsetup:
.. _setup:
.. _`setup functions`:
.. _`@pytest.setup`:

``@setup`` functions or: xunit on steroids
========================================================

.. versionadded:: 2.3

.. _`funcargs`: funcargs.html
.. _`test parametrization`: funcargs.html#parametrizing-tests
.. _`unittest plugin`: plugin/unittest.html
.. _`xUnit`: http://en.wikipedia.org/wiki/XUnit

Python, Java and many other languages support a so called xUnit_ style 
of resource setup.  This typically involves the call of a ``setup``
("fixture") method before running a test function and ``teardown`` after
it has finished.  Unlike :ref:`injected resources <resources>` setup
functions work indirectly by causing global side effects or 
setting test case attributes which test methods can then access.  

pytest originally introduced in 2005 a scope-specific model of detecting
setup and teardown functions on a per-module, class or function basis.
The Python unittest package and nose have subsequently incorporated them.
This model remains supported by pytest as :ref:`old-style xunit`.

Moreover, pytest-2.3 introduces a new ``pytest.setup()`` decorator
to mark functions as setup functions which allow to implement everything
you can do with the old-style and much more.  Specifically setup functions:

- can receive :ref:`resources through funcargs <resources>`,
- fully interoperate with parametrized resources,
- can be defined in a plugin or :ref:`conftest.py <conftest.py>` file and get called 
  on a per-session, per-module, per-class or per-function basis,
- can access the :ref:`testcontext <testcontext>` for which the setup is called,
- can precisely control teardown by registering one or multiple 
  teardown functions as soon as they have performed some actions 
  which need undoing, eliminating the no need for a separate 
  "teardown" decorator.
- allow to separate different setup concerns even if they
  happen to work in the same scope

All of these features are now demonstrated by little examples.

.. _`new_setup`:
.. _`@pytest.setup`:

basic per-function setup
-------------------------------

.. regendoc:wipe

Suppose you want to have a clean directory with a single
file entry for each test function in a module and have
the test execute with this directory as current working dir::

    # content of test_funcdir.py
    import pytest
    import os

    @pytest.setup()
    def mydir(tmpdir):
        tmpdir.join("myfile").write("example content")
        old = tmpdir.chdir()

    def test_function1():
        assert os.path.exists("myfile")
        f = open("anotherfile", "w")
        f.write("")
        f.close()

    def test_function2():
        assert os.path.exists("myfile")
        assert not os.path.exists("anotherfile")

Our ``mydir`` setup function is executed on a per-function basis,
the default scope used by the ``pytest.setup`` decorator.
It accesses the ``tmpdir`` resource which provides a new empty
directory path object.  The ``test_function2`` here checks that 
it executes with a fresh directory and that it
does not see the previously created ``anotherfile``.  We can
thus expect two passing tests::

    $ py.test -v
    =========================== test session starts ============================
    platform linux2 -- Python 2.7.3 -- pytest-2.3.0.dev7 -- /home/hpk/venv/1/bin/python
    cachedir: /home/hpk/tmp/doc-exec-410/.cache
    plugins: xdist, bugzilla, cache, oejskit, cli, pep8, cov
    collecting ... collected 2 items
    
    test_funcdir.py:9: test_function1 PASSED
    test_funcdir.py:15: test_function2 PASSED
    
    ========================= 2 passed in 0.26 seconds =========================

per-function setup, for every function of a project
------------------------------------------------------------

If you want to define a setup per-function but want to apply
it to every function in your project you don't need to duplicate
the setup-definition into each test module.  Instead you can put
it into a ``conftest.py`` file into the root of your project::

    # content of conftest.py
    import pytest
    import os

    @pytest.setup()
    def cleandir(tmpdir):
        old = tmpdir.chdir()

The ``cleandir`` setup function will be called for every test function
below the directory tree where ``conftest.py`` resides.  In this
case it just uses the builtin ``tmpdir`` resource to change to the
empty directory ahead of running a test.

test modules accessing a global resource
-------------------------------------------------------

.. note::

    Relying on `global state is considered bad programming practise <http://en.wikipedia.org/wiki/Global_variable>`_ but when you work with an application
    that relies on it you often have no choice.

If you want test modules to access a global resource,
you can stick the resource to the module globals in
a per-module setup function.  We use a :ref:`resource factory
<@pytest.factory>` to create our global resource::

    # content of conftest.py
    import pytest

    class GlobalResource:
        def __init__(self):
            pass

    @pytest.factory(scope="session")
    def globresource():
        return GlobalResource()

    @pytest.setup(scope="module")
    def setresource(testcontext, globresource):
        testcontext.module.globresource = globresource
       
Now any test module can access ``globresource`` as a module global::

    # content of test_glob.py

    def test_1():
        print ("test_1 %s" % globresource)
    def test_2():
        print ("test_2 %s" % globresource)

Let's run this module without output-capturing::

    $ py.test -qs test_glob.py
    collecting ... collected 2 items
    ..
    2 passed in 0.02 seconds
    test_1 <conftest.GlobalResource instance at 0x13197e8>
    test_2 <conftest.GlobalResource instance at 0x13197e8>

The two tests see the same global ``globresource`` object.

Parametrizing the global resource
+++++++++++++++++++++++++++++++++++++++++++++++++

We extend the previous example and add parametrization to the globresource 
factory and also add a finalizer::

    # content of conftest.py

    import pytest

    class GlobalResource:
        def __init__(self, param):
            self.param = param

    @pytest.factory(scope="session", params=[1,2])
    def globresource(testcontext):
        g = GlobalResource(testcontext.param)
        def fin():
            print "finalizing", g
        testcontext.addfinalizer(fin)
        return g

    @pytest.setup(scope="module")
    def setresource(testcontext, globresource):
        testcontext.module.globresource = globresource

And then re-run our test module::

    $ py.test -qs test_glob.py
    collecting ... collected 4 items
    ....
    4 passed in 0.02 seconds
    test_1 <conftest.GlobalResource instance at 0x1922e18>
    test_2 <conftest.GlobalResource instance at 0x1922e18>
    finalizing <conftest.GlobalResource instance at 0x1922e18>
    test_1 <conftest.GlobalResource instance at 0x1925518>
    test_2 <conftest.GlobalResource instance at 0x1925518>
    finalizing <conftest.GlobalResource instance at 0x1925518>

We are now running the two tests twice with two different global resource
instances.  Note that the tests are ordered such that only
one instance is active at any given time: the finalizer of 
the first globresource instance is called before the second
instance is created and sent to the setup functions.