Warm tip: This article is reproduced from stackoverflow.com, please click

发布于 2020-03-27 10:16:18

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

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