How to Properly Assert That an Exception Gets Raised in Pytest

How to properly assert that an exception gets raised in pytest?

pytest.raises(Exception) is what you need.

Code

import pytest

def test_passes():
with pytest.raises(Exception) as e_info:
x = 1 / 0

def test_passes_without_info():
with pytest.raises(Exception):
x = 1 / 0

def test_fails():
with pytest.raises(Exception) as e_info:
x = 1 / 1

def test_fails_without_info():
with pytest.raises(Exception):
x = 1 / 1

# Don't do this. Assertions are caught as exceptions.
def test_passes_but_should_not():
try:
x = 1 / 1
assert False
except Exception:
assert True

# Even if the appropriate exception is caught, it is bad style,
# because the test result is less informative
# than it would be with pytest.raises(e)
# (it just says pass or fail.)

def test_passes_but_bad_style():
try:
x = 1 / 0
assert False
except ZeroDivisionError:
assert True

def test_fails_but_bad_style():
try:
x = 1 / 1
assert False
except ZeroDivisionError:
assert True

Output

============================================================================================= test session starts ==============================================================================================
platform linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4
collected 7 items

test.py ..FF..F

=================================================================================================== FAILURES ===================================================================================================
__________________________________________________________________________________________________ test_fails __________________________________________________________________________________________________

def test_fails():
with pytest.raises(Exception) as e_info:
> x = 1 / 1
E Failed: DID NOT RAISE

test.py:13: Failed
___________________________________________________________________________________________ test_fails_without_info ____________________________________________________________________________________________

def test_fails_without_info():
with pytest.raises(Exception):
> x = 1 / 1
E Failed: DID NOT RAISE

test.py:17: Failed
___________________________________________________________________________________________ test_fails_but_bad_style ___________________________________________________________________________________________

def test_fails_but_bad_style():
try:
x = 1 / 1
> assert False
E assert False

test.py:43: AssertionError
====================================================================================== 3 failed, 4 passed in 0.02 seconds ======================================================================================

Note that e_info saves the exception object so you can extract details from it. For example, if you want to check the exception call stack or another nested exception inside.

Assert exception message?

I think what you're looking for is:

def failer():
raise myModule.CustomException()

def test_failer():
with pytest.raises(myModule.CustomException) as excinfo:
failer()

assert str(excinfo.value) == "boo!"

How do I test exceptions and errors using pytest?

This way:

with pytest.raises(<YourException>) as exc_info:
<your code that should raise YourException>

exception_raised = exc_info.value
<do asserts here>

Capture a custom exception with 'pytest.raises()' and assert the error message

As mentioned in my question, a comparison of the exception captured by pytest.raises() seemed to differ from that which was imported from my code. I must confess, I'm not a Python expect and I don't understand why exactly this worked, but the solution was to add init.py to the core module, and in there import all of the modules in that package.

from core.exception import *
from core.logging import *
# etc.

And then in tests/unit/test_requests.py I was able to import all objects from the core package.

from myfunction.core import *

Now pytest sees the exception it captured and the imported exception as the same and my tests are passing.

Test for proper exception with Pytest

For catching the exception, you can use pytest.raises() like follows:

def test_n_is_a_string_returns_proper_exception(client) -> None:
test_url = f"{fibonacci_url}?n=str"
with pytest.raises(ValueError):
response = client.get(test_url)

You can even check the exception message:

def test_n_is_a_string_returns_proper_exception(client) -> None:
test_url = f"{fibonacci_url}?n=str"
with pytest.raises(ValueError, match="^The value of 'n' must be an integer\.$"):
response = client.get(test_url)

But the ValueError being thrown inside your view is probably not what you wanted, as it will be shown as a generic 500 error.



Related Topics



Leave a reply



Submit