Reputation: 75
I'm new at testing and wondering if it is possible to parametrize values that should return a value, and others that should return an error to a single test.
Let's say I have a simple function divide_hundred_by(x)
, defined as follows:
def divide_hundred_by(x):
if x == 0:
raise ZeroDivisionError('You cannot divide by zero')
return 100/x
Now, I'd like to test this function for a couple of values for x and parametrize this test. I found that I can use:
import pytest
@pytest.mark.parametrize('value, expected',
[
(10, 10),
(-2, -50),
(0.5, 200)
]
)
def test_divide_hundred_by(value, expected):
with pytest.raises(ZeroDivisionError):
divide_hundred_by(0)
assert divide_hundred_by(value) == expected
But this ensures that if the warning-part fails, the entire test fails for all values, which is not what I'd like.
I'm wondering if it is possible to write something of the form:
@pytest.mark.parametrize('value, expected',
[
(10, 10),
(-2, -50),
(0.5, 200),
(0, "ZeroDivisionError")
]
)
def test_divide_hundred_by(value, expected):
assert divide_hundred_by(value) == expected
such that the test will pass for the other parameters. I cannot find anything online on the matter.
Upvotes: 7
Views: 3232
Reputation: 169267
How about this – you can check the type of expected
and if it smells like an exception class, use pytest.raises()
instead:
import pytest
def divide_hundred_by(x):
if x == 0:
raise ZeroDivisionError("You cannot divide by zero")
return 100 / x
@pytest.mark.parametrize(
"value, expected",
[
(10, 10),
(-2, -50),
(0.5, 200),
(0, ZeroDivisionError),
],
)
def test_divide_hundred_by(value, expected):
if type(expected) == type and issubclass(expected, Exception):
with pytest.raises(expected):
divide_hundred_by(value)
else:
assert divide_hundred_by(value) == expected
If you have more of this sort of thing, you can refactor the if/with/else
bit into a helper function:
import pytest
def divide_hundred_by(x):
if x == 0:
raise ZeroDivisionError("You cannot divide by zero")
return 100 / x
def check(fn, expected, args=(), kwargs={}):
if type(expected) == type and issubclass(expected, Exception):
with pytest.raises(expected):
fn(*args, **kwargs)
else:
assert fn(*args, **kwargs) == expected
@pytest.mark.parametrize(
"value, expected",
[(10, 10), (-2, -50), (0.5, 200), (0, ZeroDivisionError)],
)
def test_divide_hundred_by(value, expected):
check(divide_hundred_by, expected, (value,))
Upvotes: 11