use type error message in pytest parametrize
Question:
I have a function which raises a TypeError when some conditions are met.
def myfunc(..args here...):
...
raise TypeError('Message')
I want to test this message using pytest parametrize.
But, because I am using other arguments also I want to have a setup like this:
testdata = [
(..args here..., 'Message'), # Message is the expected output
]
@pytest.mark.parametrize(
"..args here..., expected_output", testdata)
def test_myfunc(
..args here..., expected_output):
obs = myfunc()
assert obs == expected_output
Simple putting the Message
as the expected output in the parametrize testdata, gives me a failing test.
Answers:
You can’t expect message error as a normal output of myfunc
. There is a special context manager for this – pytest.raises
.
For example, if you want to expect some error and its message
def test_raises():
with pytest.raises(Exception) as excinfo:
raise Exception('some info')
assert str(excinfo.value) == 'some info'
So, in your case, this is going to be something like
testdata = [
(..args here..., 'Message')
]
@pytest.mark.parametrize("..args here..., expected_exception_message", testdata)
def test_myfunc(..args here..., expected_exception_message):
with pytest.raises(TypeError) as excinfo:
obs = myfunc(..args here...)
assert str(excinfo.value) == expected_exception_message
The following is from the pytest docs here:
Parametrizing conditional raising
Use pytest.raises()
with the pytest.mark.parametrize
decorator to write parametrized tests in which some tests raise exceptions and others do not.
It may be helpful to use nullcontext
as a complement to raises
.
For example:
from contextlib import nullcontext as does_not_raise
import pytest
@pytest.mark.parametrize(
"example_input,expectation",
[
(3, does_not_raise()),
(2, does_not_raise()),
(1, does_not_raise()),
(0, pytest.raises(ZeroDivisionError)),
],
)
def test_division(example_input, expectation):
"""Test how much I know division."""
with expectation:
assert (6 / example_input) is not None
In the example above, the first three test cases should run unexceptionally, while the fourth should raise ZeroDivisionError
.
But that didn’t quite work for me…
The example in the Pytest docs caused me to get the error AttributeError: __enter__
.
It seems that my Python’s nullcontext
doesn’t have an __enter__
method implemented. Therefore I had to create my own version like this:
class MyNullContext:
def __enter__(self, *args, **kwargs):
pass
def __exit__(self, *args, **kwargs):
pass
does_not_raise = MyNullContext()
and use that instead of importing the builtin nullcontext
. You could throw that in a conftest.py
file so that it’s available for all your tests.
I have a function which raises a TypeError when some conditions are met.
def myfunc(..args here...):
...
raise TypeError('Message')
I want to test this message using pytest parametrize.
But, because I am using other arguments also I want to have a setup like this:
testdata = [
(..args here..., 'Message'), # Message is the expected output
]
@pytest.mark.parametrize(
"..args here..., expected_output", testdata)
def test_myfunc(
..args here..., expected_output):
obs = myfunc()
assert obs == expected_output
Simple putting the Message
as the expected output in the parametrize testdata, gives me a failing test.
You can’t expect message error as a normal output of myfunc
. There is a special context manager for this – pytest.raises
.
For example, if you want to expect some error and its message
def test_raises(): with pytest.raises(Exception) as excinfo: raise Exception('some info') assert str(excinfo.value) == 'some info'
So, in your case, this is going to be something like
testdata = [
(..args here..., 'Message')
]
@pytest.mark.parametrize("..args here..., expected_exception_message", testdata)
def test_myfunc(..args here..., expected_exception_message):
with pytest.raises(TypeError) as excinfo:
obs = myfunc(..args here...)
assert str(excinfo.value) == expected_exception_message
The following is from the pytest docs here:
Parametrizing conditional raising
Use pytest.raises()
with the pytest.mark.parametrize
decorator to write parametrized tests in which some tests raise exceptions and others do not.
It may be helpful to use nullcontext
as a complement to raises
.
For example:
from contextlib import nullcontext as does_not_raise
import pytest
@pytest.mark.parametrize(
"example_input,expectation",
[
(3, does_not_raise()),
(2, does_not_raise()),
(1, does_not_raise()),
(0, pytest.raises(ZeroDivisionError)),
],
)
def test_division(example_input, expectation):
"""Test how much I know division."""
with expectation:
assert (6 / example_input) is not None
In the example above, the first three test cases should run unexceptionally, while the fourth should raise ZeroDivisionError
.
But that didn’t quite work for me…
The example in the Pytest docs caused me to get the error AttributeError: __enter__
.
It seems that my Python’s nullcontext
doesn’t have an __enter__
method implemented. Therefore I had to create my own version like this:
class MyNullContext:
def __enter__(self, *args, **kwargs):
pass
def __exit__(self, *args, **kwargs):
pass
does_not_raise = MyNullContext()
and use that instead of importing the builtin nullcontext
. You could throw that in a conftest.py
file so that it’s available for all your tests.