I'm starting on testing a project and chose pytest. While diving into it and trying to cut down on code duplication and verbosity while testing a generator I found that I can pass params to a fixture to test different instances of the generator. Until now I'm puzzled though how I can map expected values against the different instances and I have the feeling I attempt it with the wrong thought.
With an example Generator like:
class SomeGenerator:
def __init__(self, stop: int):
self.stop = stop
def __iter__(self):
for i in range(self.stop):
yield i
Im trying to do something like this:
class TestGenerator:
@pytest.fixture(params=[3, 4])
def dummy_generator(self, request):
return SomeGenerator(request.param)
@pytest.fixture
def dummy_generator_listed(self, dummy_generator):
return list(dummy_generator)
@pytest.fixture
def dummy_generator_expected_list_1(self):
return [0, 1, 2]
@pytest.fixture
def dummy_generator_expected_list_2(self):
return [0, 1, 2, 3]
# @pytest.mark.parametrize(??)
def test_dummy_generator_output(self, dummy_generator_listed, expected_list):
pass
# something like: assert expected_list == dummy_generator_listed
The closest attempt is this:
class TestGeneratorNotWorking:
@pytest.fixture(params=[3, 4])
def dummy_generator(self, request):
return SomeGenerator(request.param)
@pytest.fixture()
def dummy_generator_listed(self, dummy_generator):
return list(dummy_generator)
@pytest.fixture()
def dummy_generator_expected_list1(self):
return [0, 1, 2]
@pytest.fixture()
def dummy_generator_expected_list2(self):
return [0, 1, 2, 3]
@pytest.mark.parametrize("expected_list", ["dummy_generator_expected_list1", "dummy_generator_expected_list2"])
def test_dummy_generator_output(self, dummy_generator_listed, expected_list, request):
assert request.getfixturevalue(expected_list) == dummy_generator_listed
This results in 4 Tests though and I only want dummy_generator_expected_list1 tested against the first instance of dummy_generator resulting in 2 Tests.
Additionally at best I would like to achieve something like this too:
@pytest.fixture(param=[dummy_generator_expected_list_1, dummy_generator_expected_list_2])
def dummy_expected_lists_grouped(self, expected_list):
return expected_list
def test_dummy_generator_output(self, dummy_generator_listed, dummy_expected_list_grouped):
pass
# something like: assert dummy_expected_list_grouped == dummy_generator_listed
A scheme like this is would be wonderful in the actual implementation as the data of the generator is quite big and verbose so it would be absolutely unreadable to attempt it like:
@pytest.mark.parametrize("expected_list", [[0, 1, 2], [0, 1, 2, 3]])
def test_dummy_generator_output(self, dummy_generator_listed, expected_list):
assert expected_list == dummy_generator_listed
And writing single tests for every expected generator and output has way too much duplication for my taste.
Thanks a lot in advance. As this is my first question posted here I hope I have given all resources needed in an understandable way
I think there is no need to use the fixture for that, as you only try to use one fixture param at a time (list1 only works while param=3). I would just parametrize both values like that:
@pytest.mark.parametrize("param, expected_list", [
(3, [0,1,2]),
(4, [0,1,2,3])
])
def test_dummy_generator_output(self, param, expected_list):
generator = SomeGenerator(param)
assert list(generator) == expected_list
Regarding your bonus addition - you can save the list of tuples in another place and just call it using the variable representing it.