pytest xUnit style fixtures

I’m going to cover the syntax for pytest support for xUnit style fixtures.
Then I’ll give a more reasonable and typical example, using just one set of fixture functions.
And then address the issue of having tests mixed in a file. Some that need the resource, and some that don’t.

Depending on what scope you want your fixtures, you define setup/teardown pairs.

  • Module (setup_module/teardown_module)
    • Sets things up once for the module, teardown after everything.
  • Function (setup_function/teardown_function)
    • Wraps every test function with calls.
    • Gets called multiple times, once for each function
  • Class (setup_class/teardown_class)
    • Like module level, but for classes, once for a class.
  • Method (setup_method/teardown_method)
    • Like function level, but for classes.
    • Gets called multiple times, once for each test method in a class

Example using module, function, class, and method fixtures

And lets run it to see the flow. I did remove some of the extra blank lines for this post.

Realistic example

Typically, you don’t throw all of the fixture types together.
Most of the time, one style is enough, depending what you are setting up, initializing, etc. and if it needs re-initialized before every test, and cleaned up after every test.

So, lets make things a bit simpler.

I’ve got a resource, called resource_a. I know, boring name. It’s just something that needs a setup and a teardown function.

This really could be any sort of resource:

  • temp file
  • temp directory
  • database connection
  • db transaction that needs rolled back after testing
  • open socket connection
  • a signal generator putting out a test signal
  • you get the drift

In this example, I’ve used method level fixtures so the setup/teardown happens at the beginning and end of the module, once for all the tests. Maybe it’s an expensive operation or something.

Here’s our simpler example with a resource.

And the output.

Adding another test function

Then we add a test that actually doesn’t need the resource:

And we re-run it.

This isn’t really a problem so far.
Since the first test needs the resource, it’s fine the way we are doing things.

Problem: the resource is set up even when we don’t need it.

If we just want to run one function, the second one, that doesn’t need the resource, the fixture is run anyway.

This is a waste.
If the fixtures are quite lengthy, it can seriously slow down the test run unnecessarily.

Creating classes to separate fixture needs

You can relatively cleanly deal with this by either isolating tests requiring a resource to their own module, or to their own class.

I’ll demonstrate the class solution to this problem.

Move the fixtures from module to class level, and move the tests that use the resource into the class.

Now we can run the test in isolation without expensive and unnecessary resource setup/cleanup.

And the resource is still dealt with correctly when we do need it.

For lots and lots of circumstances, resource handling in this manner is completely sufficient.

However, I do believe that the pytest fixture mechanism (which I’ll cover in my next post), is a more elegant and scalable solution to the problem.

Comments

Leave a Reply