Reputation: 26823
For example, say I have two functions:
def func3(a, b, c):
for var in (a, b, c):
if var < 0:
raise ValueError
pass
def func7(a, b, c, d, e, f, g):
for var in (a, b, c, d, e, f, g):
if var < 0:
raise ValueError
pass
And in my tests, I want to test a set of invalid values at each parameter. The only way I know of to do this is to write them all out:
@pytest.mark.parametrize('val', [-2, -3, -4.5])
def test_invalid_param(val):
with pytest.raises(ValueError):
func3(val, 0, 0)
with pytest.raises(ValueError):
func3(0, val, 0)
with pytest.raises(ValueError):
func3(0, 0, val)
with pytest.raises(ValueError):
func7(val, 0, 0, 0, 0, 0, 0)
with pytest.raises(ValueError):
func7(0, val, 0, 0, 0, 0, 0)
with pytest.raises(ValueError):
func7(0, 0, val, 0, 0, 0, 0)
...
How can I combine these all into one with pytest.raises
case?
If both funcs had the same number of arguments, I could stack this:
@pytest.mark.parametrize('func', [func3, func7])
but they don't. If they just had different numbers of arguments and I was only testing the first, then I could stack this:
@pytest.mark.parametrize('func, args', [(func3, (0, 0)),
(func7, (0, 0, 0, 0, 0, 0))])
But that won't work for testing the parametrized value in multiple positions.
Upvotes: 0
Views: 347
Reputation: 50899
If you don't mind increasing the number of tests you can use the values sets as a parameter to the test. Each set will be a different test
def data_source():
for val in [-2, -3, -4.5]:
for values_set in [[val, 0, 0], [0, val, 0], [0, 0, val], [val, 0, 0, 0, 0, 0, 0], [0, val, 0, 0, 0, 0, 0], [0, 0, val, 0, 0, 0, 0]]:
yield values_set
def func(values):
for var in values:
if var < 0:
raise ValueError
pass
@pytest.mark.parametrize('values', data_source())
def test_invalid_param(values):
with pytest.raises(ValueError):
func(values)
In case of failure the stack trace will look like
(test_invalid_param[values6])
values = [3, 0, 0]
@pytest.mark.parametrize('values', data_source())
def test_invalid_param(values):
with pytest.raises(ValueError):
> func(*values)
E Failed: DID NOT RAISE <class 'ValueError'>
Example_test.py:32: Failed
As a side note, to allow different number of arguments you can use *
in the parameter
def func(*values):
for var in values:
if var < 0:
raise ValueError
pass
Upvotes: 2