How to use pytest to check that Error is NOT raised
Categories:
Ensuring Code Robustness: How to Assert No Exceptions with pytest

Learn how to effectively use pytest to verify that your Python code does NOT raise specific exceptions, ensuring stability and correctness in your applications.
When writing tests, it's common to assert that certain operations raise expected exceptions. However, an equally important aspect of testing is to ensure that your code doesn't raise an exception when it's not supposed to. This is crucial for verifying the stability and correct behavior of functions under normal operating conditions. This article will guide you through various pytest techniques to assert the absence of exceptions.
The Basic Approach: No pytest.raises
The simplest way to assert that no exception is raised is to simply execute the code without wrapping it in pytest.raises
. If the code under test executes successfully without an unhandled exception, the test passes. If an unexpected exception occurs, the test will fail, indicating a problem.
import pytest
def safe_function(x):
if x < 0:
raise ValueError("Input cannot be negative")
return x * 2
def test_safe_function_no_exception():
# This test passes if no exception is raised
result = safe_function(5)
assert result == 10
def test_safe_function_with_exception():
# This test expects a ValueError
with pytest.raises(ValueError):
safe_function(-1)
Basic test demonstrating successful execution and expected exception handling.
pytest.raises
' approach is often the most straightforward and Pythonic way to test for the absence of exceptions. It leverages the default behavior of the test runner.Asserting Specific Exceptions Are NOT Raised
While the basic approach works for any unexpected exception, sometimes you might want to explicitly state that a particular exception type should not be raised. This can be useful in scenarios where you've refactored code to prevent a specific error, or when you want to be very explicit about the expected behavior. Pytest doesn't have a direct pytest.does_not_raise
context manager, but you can achieve this using a combination of try...except
and pytest.fail
.
import pytest
def process_data(data):
if not isinstance(data, list):
raise TypeError("Data must be a list")
if not data:
raise ValueError("Data list cannot be empty")
return [item.upper() for item in data]
def test_process_data_no_type_error():
try:
process_data(["apple", "banana"])
except TypeError:
pytest.fail("TypeError was unexpectedly raised!")
def test_process_data_no_value_error():
try:
process_data(["one", "two"])
except ValueError:
pytest.fail("ValueError was unexpectedly raised!")
def test_process_data_expected_type_error():
with pytest.raises(TypeError):
process_data("not a list")
def test_process_data_expected_value_error():
with pytest.raises(ValueError):
process_data([])
Using try...except
with pytest.fail
to assert the absence of specific exceptions.
flowchart TD A[Start Test] --> B{Execute Code Under Test} B --> C{Exception Raised?} C -- Yes --> D{Is it an Expected Exception?} D -- Yes --> E[Test Passes (e.g., with pytest.raises)] D -- No --> F[Test Fails (Unexpected Exception)] C -- No --> G[Test Passes (No Exception)]
Decision flow for pytest exception handling.
Testing for No Exception in a More Generic Way
If you want to ensure that any exception is not raised, but still want to use a context manager-like syntax for clarity, you can create a custom helper. While pytest.raises
is designed for expecting an exception, you can invert its logic or use a simple try...except
block to catch any Exception
and then fail the test.
import pytest
def potentially_problematic_function(value):
if value == 0:
return 1 / value # This will raise ZeroDivisionError
if not isinstance(value, (int, float)):
raise TypeError("Input must be a number")
return value * 10
def test_no_exception_generic():
try:
potentially_problematic_function(5)
potentially_problematic_function(10.5)
except Exception as e:
pytest.fail(f"An unexpected exception was raised: {e}")
def test_expected_zero_division_error():
with pytest.raises(ZeroDivisionError):
potentially_problematic_function(0)
def test_expected_type_error():
with pytest.raises(TypeError):
potentially_problematic_function("text")
A generic approach to ensure no exceptions are raised using try...except Exception
.
try...except Exception
is generic, be cautious not to mask legitimate errors that should cause a test to fail. Use it when you truly expect no error of any kind.