I'm looking for more elegant solution for this kind of problem:
def ids(x):
if isinstance(x, int):
return str(x)
elif isinstance(x, str):
return x[0]
@pytest.mark.parametrize("number, string",
[
(1, "One"),
(2, "Two"),
(3, "Three")
],
ids=ids)
def test_stupid(number, string):
assert 0 == 1
This code will produce test names: '1-O', '2-T', '3-T'.
The problem is that pytest is using same function for all arguments in tuple and I have to deal with ugly isinstance calls.
Is there a better way to solve this problem?
You can pass arguments to fixtures with the params keyword argument in the fixture decorator, and you can also pass arguments to tests with the @pytest. mark. parametrize decorator for individual tests.
@pytest. mark. parametrize allows one to define multiple sets of arguments and fixtures at the test function or class. pytest_generate_tests allows one to define custom parametrization schemes or extensions.
conftest.py is where you setup test configurations and store the testcases that are used by test functions. The configurations and the testcases are called fixture in pytest.
Pass a list of strings instead of a callable as ids
:
import pytest
PARAMS = [
(1, "One"),
(2, "Two"),
(3, "Three")
]
def my_id(number, string):
return '-'.join([str(number), string[0]])
@pytest.mark.parametrize("number, string",
PARAMS,
ids=[my_id(number, string) for number, string in PARAMS])
def test_stupid(number, string):
assert 0 == 1
The only solution i've found is to use hook pytest_collection_modifyitems(session, config, items)
It has access to parameters values, and can be used to change test names. But it relies on internal details of pytest Function class implementation and thus is not very robust.
I add pytest.mark with format string and converters for each parameter. All parameters optional
@pytest.mark.parametrize("number, string",
[
(1, "One"),
(2, "Two"),
(3, "Three")
])
@pytest.mark.params_format('number={number} string={string}',
number=lambda x: str(x),
string=lambda x: x[0])
def test_stupid(number, string):
And then add to conftest.py
hook implementation to use that mark parameters and add formatted string to test
def pytest_collection_modifyitems(session, config, items):
for item in items:
if not _get_marker(item, 'parametrize'):
continue
format_params_marker = _get_marker(item, 'params_format')
if not format_params_marker:
continue
params = item.callspec.params.copy()
param_formatters = format_params_marker.kwargs
for param_name, presenter in param_formatters.iteritems():
params[param_name] = presenter(params[param_name])
params_names_ordered = [name for name in item.fixturenames if name in params]
default_format = '-'.join(['{{{}}}'.format(param_name) for param_name in params_names_ordered])
format_string = format_params_marker.args[0] if format_params_marker.args \
else default_format
item.name = '{func}[{params}]'.format(func=item.name.split('[')[0],
params=format_string.format(**params))
def _get_marker(item, marker):
return item.keywords._markers.get(marker, None)
The result will look something like this
test_stupid[number=1 string=O] PASSED
test_stupid[number=2 string=T] PASSED
test_stupid[number=3 string=T] PASSED
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With