QA Graphic

Using pytest.raises to Validate Exceptions Like a Pro

Negative Tests are useful too!

As a QA Engineer or automation enthusiast, writing tests that validate correct behavior is only half the battle. The other half? Making sure the app handles wrong behavior gracefully. That's where negative testing comes in - and pytest.raises is your secret weapon.

In this post, we'll explore how pytest.raises lets you assert exceptions are raised without failing the test. This is perfect for validating edge cases, bad input, or failed operations.

What is pytest.raises?

In Pytest, if your code raises an exception during a test, the test normally fails - as it should. But what if you're expecting the exception? That's where pytest.raises comes in.

It wraps a block of code and passes the test only if the specified exception is raised. If it's not raised, the test fails.

Why Use pytest.raises?

  • Makes negative testing clean and readable
  • Helps document edge-case handling
  • Prevents false positives in error conditions
  • Encourages testing of robust, defensive code

A Real-World Example

Let's say we're testing a simple division function that raises a ZeroDivisionError when the denominator is zero.

def safe_divide(x, y):
    return x / y

Now for the test:

import pytest
def test_safe_divide_zero_division():
    with pytest.raises(ZeroDivisionError):
        safe_divide(10, 0)

This test will pass if safe_divide(10, 0) throws ZeroDivisionError. If it doesn't (for example, if the code silently returns None), the test fails - telling us something's broken.

Accessing the Exception

You can even inspect the exception message or attributes:

def test_value_error_with_message():
    with pytest.raises(ValueError) as excinfo:
        int("hello")  # not a valid integer
    assert "invalid literal" in str(excinfo.value)

This is powerful when you want to verify the type and details of the exception.

Clean Up with pytest.raises

Before pytest.raises, Python developers would clutter tests with try/except blocks and fail manually. Compare:

Old way:

def test_safe_divide_old():
    try:
        safe_divide(10, 0)
        assert False, "Expected ZeroDivisionError"
    except ZeroDivisionError:
        pass

Pytest way:

def test_safe_divide_pytest():
    with pytest.raises(ZeroDivisionError):
        safe_divide(10, 0)

Much cleaner, right?

Use Case Ideas for pytest.raises

  • Invalid API parameters (TypeError, ValueError)
  • Database connection failures (ConnectionError)
  • File not found or permission issues (IOError, PermissionError)
  • Custom business rule exceptions

Final Thought

In automation testing, you should never be afraid of exceptions - you should expect them when the input is bad. pytest.raises gives you the confidence to write bold, bulletproof test cases that ensure your code handles errors on purpose - not by accident.

Have a favorite exception handling trick or a real bug you caught using pytest.raises? Share it in the comments below.

 

Comments

Add Your Comments

Name:
Comment:

 

About

Welcome to Pytest Tips and Tricks, your go-to resource for mastering the art of testing with Pytest! Whether you're a seasoned developer or just dipping your toes into the world of Python testing, this blog is designed to help you unlock the full potential of Pytest - one of the most powerful and flexible testing frameworks out there. Here, I'll share a treasure trove of practical insights, clever techniques, and time-saving shortcuts that I've gathered from years of writing tests and debugging code.

Schedule

Tuesday 22 QA
Wednesday 23 Pytest
Thursday 24 PlayWright
Friday 25 Macintosh
Saturday 26 Internet Tools
Sunday 27 Misc
Monday 28 Media