Home > Software design >  Is there a way to test `raise X from Y` using pytest?
Is there a way to test `raise X from Y` using pytest?

Time:10-30

I would like to know if there is a better way and what the options are for testing raise X from Y using pytest.

Here's a dummy example:

import pytest

class AException(Exception):
    pass

class A:
    def __init__(self) -> None:
        raise AException("Class A")

class C:
    def __init__(self) -> None:
        try:
            A()
        except AException as err:
            raise ValueError("C Failed") from err

def test_class_c():
    with pytest.raises(ValueError):
        C()

In this example, the test should confirm that it raised ValueError from AException from Class A.

The obvious solution is to pass the message like this:

except AException as err:
    raise ValueError(f"C Failed: {err}") from err

and then match it:

def test_class_c():
    with pytest.raises(ValueError, match="Class A"):
        C()

but is there another way?

CodePudding user response:

I haven't come across an official way of doing this but one way could be to check __cause__ (or __context__) of the most "recent" exception:

def test_class_c():
    with pytest.raises(ValueError) as exc_info:
        C()
    assert isinstance(exc_info.value.__cause__, AException)
    assert exc_info.value.__cause__.args == ("Class A",)

PEP regarding __cause__ and __context__: https://www.python.org/dev/peps/pep-3134/

What is the difference between __cause__ and __context__?

  • Related