Pytest
Exception Handling
Unit Testing
Python Programming
Code Debugging

How do I properly assert that an exception gets raised in pytest?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In pytest, the standard way to assert that code raises an exception is pytest.raises. It is simple, but getting the details right matters. Good exception tests should prove both that the right exception type is raised and that the failure happens for the reason you expect.

The Core Pattern: pytest.raises

The basic form is a context manager around the exact line or block that should fail.

python
1import pytest
2
3
4def divide(a, b):
5    if b == 0:
6        raise ValueError("division by zero is not allowed")
7    return a / b
8
9
10def test_divide_raises_for_zero():
11    with pytest.raises(ValueError):
12        divide(10, 0)

This test passes only if divide(10, 0) raises ValueError. If no exception is raised, or if a different exception type appears, the test fails.

That is already better than a try/except block because pytest produces clearer failure output and avoids hand-written assertion plumbing.

Assert on the Message Too

Checking the exception type alone is often not enough. If your function can raise the same exception type for multiple reasons, assert on the message or some other attribute.

python
1import pytest
2
3
4def parse_port(value):
5    if not value.isdigit():
6        raise ValueError("port must contain only digits")
7    return int(value)
8
9
10def test_parse_port_message():
11    with pytest.raises(ValueError, match="only digits"):
12        parse_port("abc")

The match= argument applies a regular expression to the exception text. That makes the test both readable and precise.

You can also capture the exception object for more detailed checks:

python
1import pytest
2
3
4def test_exception_object():
5    with pytest.raises(ValueError) as exc_info:
6        parse_port("abc")
7
8    assert "digits" in str(exc_info.value)

Keep the with Block Small

A subtle best practice is to keep only the failure-triggering code inside the with pytest.raises(...) block.

Bad shape:

python
1with pytest.raises(ValueError):
2    config = load_config()
3    result = validate(config)
4    save_result(result)

If this test passes, you do not know which line actually raised the exception.

Better shape:

python
1config = load_config()
2
3with pytest.raises(ValueError):
4    validate(config)

Now the intent is explicit and the test is easier to trust.

Testing Custom Exceptions

pytest.raises works the same way for your own exception classes.

python
1import pytest
2
3
4class InvalidStateError(Exception):
5    pass
6
7
8def do_work(state):
9    if state != "ready":
10        raise InvalidStateError("state must be ready")
11
12
13def test_custom_exception():
14    with pytest.raises(InvalidStateError, match="must be ready"):
15        do_work("stopped")

The pattern stays the same: specific type first, optional message or attribute checks second.

What Not to Do

Avoid broad exception assertions such as pytest.raises(Exception) unless the code genuinely may raise several unrelated exceptions and that is what you are testing. Broad catches make tests pass when the code fails for the wrong reason.

Also avoid manual try/except patterns like this:

python
1try:
2    divide(10, 0)
3    assert False, "expected ValueError"
4except ValueError:
5    pass

It works, but it is noisier and weaker than the built-in pytest tool.

Common Pitfalls

The most common mistake is putting too much code inside the with pytest.raises(...) block, which makes it unclear what actually failed.

Another mistake is asserting only on the exception type when multiple branches can raise that type for different reasons.

A third pitfall is using a broad base exception, which can hide regressions by accepting the wrong failure mode.

Summary

  • Use pytest.raises to assert that code raises an exception.
  • Keep the with block focused on the exact line or call that should fail.
  • Use match= or exc_info when you need to verify the message or attributes.
  • Prefer specific exception classes over broad ones such as Exception.
  • Avoid manual try/except assertion patterns when pytest already provides the right tool.

Course illustration
Course illustration

All Rights Reserved.