5
votes

I'm trying to create a test environment with Pytest. The idea is to group test methods into classes.

For every class/group, I want to attach a config fixture that is going to be parametrized. So that I can run all the tests with "configuration A" and then all tests with "configuration B" and so on.

But also, I want a reset fixture, that can be executed before specific methods or all methods of a class.

The problem I have there is, once I apply my reset fixture (to a method or to a whole class), the config fixture seems to work in the function scope instead of the class scope. So, once I apply the reset fixture, the config fixture is called before/after every method in the class.

The following piece of code reproduces the problem:

import pytest
from pytest import *

@fixture(scope='class')
def config(request):
    print("\nconfiguring with %s" % request.param)
    yield
    print("\ncleaning up config")

@fixture(scope='function')
def reset():
    print("\nreseting")

@mark.parametrize("config", ["config-A", "config-B"], indirect=True)
#@mark.usefixtures("reset")
class TestMoreStuff(object):

    def test_a(self, config):
        pass

    def test_b(self, config):
        pass

    def test_c(self, config):
        pass

The test shows how the config fixture should work, being executed only once for the whole class. If you uncomment the usefixtures decoration, you can notice that the config fixture will be executed in every test method. Is it possible to use the reset fixture without triggering this behaviour?

2
This is actually a bug in Pytest 3.2.5: github.com/pytest-dev/pytest/issues/2938 - Gustavo Meira

2 Answers

5
votes

As I mentioned in a comment, that seems to be a bug in Pytest 3.2.5.

There's a workaround, which is to "force" the scope of a parametrization. So, in this case if you include the scope="class" in the parametrize decorator, you get the desired behaviour.

import pytest
from pytest import *

@fixture(scope='class')
def config(request):
    print("\nconfiguring with %s" % request.param)
    yield
    print("\ncleaning up config")

@fixture(scope='function')
def reset():
    print("\nreseting")

@mark.parametrize("config", ["config-A", "config-B"], indirect=True, scope="class")
@mark.usefixtures("reset")
class TestMoreStuff(object):

    def test_a(self, config):
        pass

    def test_b(self, config):
        pass

    def test_c(self, config):
        pass
0
votes

It depends on which version of pytest you are using.

There are some semantical problems to implement this in older versions of pytest. So, this idea is not yet implemented in older pytest. Someone has already given suggestion to implement the same. you can refer this

"Fixture scope doesn't work when parametrized tests use parametrized fixtures". This was the bug. You can refer this

This issue has been resolved in latest version of pytest. Here's the commit for the same with pytest 3.2.5

Hope it would help you.