23

I have tests that I want to parameterize, but there are certain tests that should only be applied to one value of the parameters. To give a specific example, below, I would like to apply parameters one and two to test_A, but only supply parameter one to test_B.

Current Code

@pytest.fixture(params=['one', 'two'])
def data(request):

    if request.param == 'one'
         data = 5
    return data

def test_A(data):

    assert True

def test_B(data):

    assert True

Desired Results

I basically want something that looks like this, but I can't figure out how to code this properly in pytest:

@pytest.fixture(params=['one', 'two'])
def data(request):

    data = 5
    return data

def test_A(data):

    assert True

@pytest.skipif(param=='two')
def test_B(data):

    assert True
ZachTurn
  • 636
  • 1
  • 5
  • 14

2 Answers2

25

Building on your answer, you can check the input and call pytest.skip() if you don't want the test to run.

You can do the check in the test:

def test_A(data):
    assert True

def test_B(data):
    if data.param == 'two':
        pytest.skip()
    assert 'foo' == 'foo'

Or you could redefine the test fixture in a subclass:

class TestA:
    def test_A(self, data):
        assert True

class TestB:
    @pytest.fixture
    def data(self, data):
        if data.param == 'two':
            pytest.skip()
        return data

    def test_B(self, data):
        assert 'foo' == 'foo'

One other minor suggestion: your Data class can be replaced with a namedtuple, i.e.

import collections
Data = collections.namedtuple('Data', 'data, param')
Frank T
  • 8,268
  • 8
  • 50
  • 67
  • If I split my tests into two separate classes, would the parameterization still apply to TestA? – ZachTurn Aug 14 '17 at 19:34
  • Yup, your `data` fixture is a parametrized test fixture, and it will remain parametrized. When you use a parametrized test fixture in another fixture, the parametrization "carries over". Using multiple parametrized fixtures generates all the resulting permutations. This answer gives some more complex examples: https://stackoverflow.com/a/22390931/1812727 – Frank T Aug 14 '17 at 19:45
1

I found a working solution, but I also welcome more solutions as this feels a tad "hacky":

class Data:

    def__init__(self, data, param):
        self.data = data
        self.param = param

@pytest.fixture(params=['one', 'two'])
def data(request):

    data = 5
    return Data(data, request.param)

def test_A(data):

    assert True

def test_B(data):

    if data.param == 'two':
        assert True
    else:
        assert 'foo' == 'foo'
ZachTurn
  • 636
  • 1
  • 5
  • 14