[TIP] pytest: Setup/TearDown with fixtures

holger krekel holger at merlinux.eu
Thu Sep 4 01:23:35 PDT 2014


Hi Floris, Laszlo,

On Wed, Sep 03, 2014 at 21:08 +0100, Floris Bruynooghe wrote:
> 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)

I guess you want to "return session" here in order for test_bar to receive it.

>     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.

I also appreciate that listing dependencies of a test function right
in the argument list makes it easy to understand what a test depends on.

By contrast, if you use autouse or xUnit style setupX methods a reader
of your test function needs to deduce that they are called.

best,
holger

> 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
> 
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python
> 



More information about the testing-in-python mailing list