Reputation: 388
I Have two similar testcases with each having more than 100 lines of code which creates aux objects for the test, those lines are very similar, in fact, only 2 lines differ between the tests setups and I wan't to get rid of the code repetition. I think that multiple parameterization might help me with this task. Using multiple parametrization I can combine setups in the one and actually provide better conditions for the test. Bun I can't wrap my head around of what is the best way to specify the expected result while using multiple parametrization when each combination will yield different results?
Consider this test case
@pytest.mark.parametrize('country', ['US', 'DE', 'FR', 'IT'])
@pytest.mark.parametrize('number', ['12345', '54321'])
def test_correct_record_is_selected_for_number(country, number):
# 100 line long setup of different objects.
record = get_record(country, number)
assert record = expected_record
I expect that for a different combinations of (country, number)
get_record
function will return different results, and the only way I see to provide the expected result - is to reimplement the part of the get_record
function logic in the test itself in order to determine which result to expect based on provided country
and number
, which doesn't seem right to me.
Is there a way to nicely specify expected output for stacked parametrize
decorators? Or I'm better off with moving setup code to multiple different fixtures and leaving it as 2 separate tests that use different setup fixtures?
Upvotes: 4
Views: 4993
Reputation: 16815
I'm not aware of a nice way, but in any case you have to list the different expected results somewhere. So you could just put them in a dictionary outside the test:
expected_record = {
'US': {
'12345': {...},
'54321': {...},
},
'DE': {
'12345': {...},
'54321': {...},
},
...
}
@pytest.mark.parametrize('country', ['US', 'DE', 'FR', 'IT'])
@pytest.mark.parametrize('number', ['12345', '54321'])
def test_correct_record_is_selected_for_number(country, number):
record = get_record(country, number)
assert record == expected_record[country][number]
Upvotes: 5
Reputation: 66261
Usually I put the results in a separate fixture that selects the expected value based on other arguments. Example:
expected_records = {'US': {'12345': 'fizz', '54321': 'buzz'}, 'DE': ...}
@pytest.fixture
def expected_record(request):
country = request.node.funcargs['country']
number = request.node.funcargs['number']
return expected_records.get(country, dict()).get(number, None)
@pytest.mark.parametrize('country', ['US', 'DE', 'FR', 'IT'])
@pytest.mark.parametrize('number', ['12345', '54321'])
def test_correct_record_is_selected_for_number(country, number, expected_record):
record = get_record(country, number)
assert record == expected_record
However, in practice the data is rarely hardcoded in the script, so the logic of expected_record
is usually data-driven, for example:
@pytest.fixture
def expected_record(request):
country = request.node.funcargs['country']
number = request.node.funcargs['number']
file = pathlib.Path(request.config.rootdir, 'data', country).with_suffix('.json') # data/DE.json
data = json.loads(file.read_text()) # {12345: "fizz", 54321: "buzz"}
return data[number]
Upvotes: 7