I'm testing code where one of two exceptions can be raised: MachineError or NotImplementedError. I would like to use pytest.raises to make sure that at least one of them is raised when I run my test code, but it only seems to accept one exception type as an argument.
This is the signature for pytest.raises:
raises(expected_exception, *args, **kwargs)
I tried using the or keyword inside a context manager:
with pytest.raises(MachineError) or pytest.raises(NotImplementedError):
verb = Verb("donner<IND><FUT><REL><SG><1>")
verb.conjugate()
but I assume this only checks whether the first pytest.raises is None and sets the second one as the context manager if it is.
Passing multiple exceptions as positional arguments doesn't work, because pytest.raises takes its second argument to be a callable. Every subsequent positional argument is passed as an argument to that callable.
From the documentation:
>>> raises(ZeroDivisionError, lambda: 1/0)
<ExceptionInfo ...>
>>> def f(x): return 1/x
...
>>> raises(ZeroDivisionError, f, 0)
<ExceptionInfo ...>
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>
Passing the exceptions as a list doesn't work either:
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
with pytest.raises([MachineError, NotImplementedError]):
File "/usr/local/lib/python3.4/dist-packages/_pytest/python.py", line 1290, in raises
raise TypeError(msg % type(expected_exception))
TypeError: exceptions must be old-style classes or derived from BaseException, not <class 'list'>
Is there a workaround for this? It doesn't have to use a context manager.
Strictly speaking you can't raise multiple exceptions but you could raise an object that contains multiple exceptions.
Pytest, by way of magic (also known as introspection) can infere the actual value, the expected value, and the operation used in a plain old assert statement and can provide a rather nice error message.
Pass the exceptions as a tuple to raises:
with pytest.raises( (MachineError, NotImplementedError) ):
verb = ...
In the source for pytest, pytest.raises may:
expected_exception; orexpected_exception to a RaisesContext instance, which then uses issubclass to check whether the exception was one you wanted. In Python 3, except statements can take a tuple of exceptions. The issubclass function can also take a tuple. Therefore, using a tuple should be acceptable in either situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With