pytest python

# Py.test: How to parametrize when some values should return an error

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.

Questioner
D.C.
Viewed
158
AKX 2019-07-03 21:19

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,))
``````