[TIP] pytest: Setup/TearDown with fixtures

Eric Larson eric at ionrock.org
Wed Sep 3 14:19:16 PDT 2014


Floris Bruynooghe writes:

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

Just to provide a slight contrast here, I've found that when creating
tests with fixtures I *do* use the instance for storing state. For
example:

  class TestSomeClassFoo(object):

      def setup(self):
          self.foo = Foo()

      @pytest.fixture()
      def bar(self, user):
          return Bar(user=user)

      def test_foo_adds_bar(self, bar):
          assert self.foo.add(bar)

In the above example, I'm assuming the `user` argument is a fixture used
in other tests as well.

That said, this usage is somewhat atypical in practice. For whatever
reason, I typically will only use fixtures for specific test objects
that I want to use in many different tests or I will create the
application state within the class via fixtures. Rarely do I use
fixtures to do setup / teardown.

With that said, it would be extremely convenient if fixtures could be
used from setup / teardown because then it would be easy to do things
like:

  class TestFoo(object):
      def setup(self, user):  # this won't work
          self.foo(user=user)

I hope my example doesn't muddy the waters. Just because pytest has an
insanely powerful feature in fixtures, it doesn't mean that you don't
need other helpful bits like setup / teardown.

Eric



More information about the testing-in-python mailing list