[TIP] pytest: Setup/TearDown with fixtures

Floris Bruynooghe flub at devork.be
Wed Sep 3 13:08:32 PDT 2014


Hello Laszlo,

All that follows is my personal opinion and may not be official best
practices.  Furthermore there are multiple ways to achieve this, what
you did clearly already worked.  Anyway, here goes:

On 2 September 2014 14:58, Laszlo Papp <lpapp at kde.org> wrote:
> Right, I think this could be added to the official documentation to
> have a copy/pasteable example in there:
>
> class TestFoo:
>     @classmethod
>     @pytest.fixture(scope="class", autouse = True)
>     def setup(self, request):
>         self.session = foo.session()
>         def tearDown():
>             session.logout()
>         request.addfinalizer(tearDown)
>
> I am yet to test this in practice, but this simple snippet would have
> been a timer-saver for me when writing this basic functionality ...

There are 2 main issues I have with this example:

1) I actively avoid using fixture names which conflict with the xUnix
or nose setup/teardown compatibility names to avoid confusion.

2) When using fixtures I treat the class purely as a container
providing structure, kind of like a module.  So storing state on the
class/instance is right out.  The power of fixtures comes explicitly
from decoupling test class instances from fixture issues
(setup/teardown) which makes fixtures much more composable due to
better separation of concerns.  This is IMHO where the power of
fixtures comes from.

With that said I would write your example as:

class TestFoo:

    @pytest.fixture(scope='class', autouse=True)
    def session(self, request):
        session = foo.session()
        request.addfinalizer(session.logout)

    def test_foo(self):
        # test code not using the session explicitly,
        # will still be created and logged out however.

    def test_bar(self, session):
        # test code using session explicitly.

Structuring the tests like this makes it explicit what your tests are
doing.  It may even transpire that all tests use the session in which
case it this could be refactored to not be an autouse fixture.

As a bonus this also avoids the confusion of class methods and their
first argument (self? cls? Am I now assigning to the class or
instance?).


As for having a clearer example in the documentation as this being the
equivalent in the documentation: it would be great if you could create
a PR with this your original xUnit example and the fixture-based
equivalent.  Then people after you will hopefully find the mental step
to convert tests from this pattern more easily.


Best regards,
Floris


-- 
Debian GNU/Linux -- The Power of Freedom
www.debian.org | www.gnu.org | www.kernel.org



More information about the testing-in-python mailing list