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

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


pytest.raises(Exception) is what you need.

Code

import pytestdef test_passes():    with pytest.raises(Exception) as e_info:        x = 1 / 0def test_passes_without_info():    with pytest.raises(Exception):        x = 1 / 0def test_fails():    with pytest.raises(Exception) as e_info:        x = 1 / 1def 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 Truedef 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.4collected 7 items test.py ..FF..F=================================================================================================== FAILURES ===================================================================================================__________________________________________________________________________________________________ test_fails __________________________________________________________________________________________________    def test_fails():        with pytest.raises(Exception) as e_info:>           x = 1 / 1E           Failed: DID NOT RAISEtest.py:13: Failed___________________________________________________________________________________________ test_fails_without_info ____________________________________________________________________________________________    def test_fails_without_info():        with pytest.raises(Exception):>           x = 1 / 1E           Failed: DID NOT RAISEtest.py:17: Failed___________________________________________________________________________________________ test_fails_but_bad_style ___________________________________________________________________________________________    def test_fails_but_bad_style():        try:            x = 1 / 1>           assert FalseE           assert Falsetest.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.


Do you mean something like this:

def test_raises():    with pytest.raises(Exception) as execinfo:           raise Exception('some info')    # these asserts are identical; you can use either one       assert execinfo.value.args[0] == 'some info'    assert str(execinfo.value) == 'some info'


There are two ways to handle these kind of cases in pytest:

  • Using pytest.raises function

  • Using pytest.mark.xfail decorator

As the documentation says:

Using pytest.raises is likely to be better for cases where you are testing exceptions your own code is deliberately raising, whereas using @pytest.mark.xfail with a check function is probably better for something like documenting unfixed bugs (where the test describes what “should” happen) or bugs in dependencies.

Usage of pytest.raises:

def whatever():    return 9/0def test_whatever():    with pytest.raises(ZeroDivisionError):        whatever()

Usage of pytest.mark.xfail:

@pytest.mark.xfail(raises=ZeroDivisionError)def test_whatever():    whatever()

Output of pytest.raises:

============================= test session starts ============================platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- /usr/local/python_2.7_10/bin/pythoncachedir: .cacherootdir: /home/user, inifile:collected 1 itemtest_fun.py::test_whatever PASSED======================== 1 passed in 0.01 seconds =============================

Output of pytest.xfail marker:

============================= test session starts ============================platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- /usr/local/python_2.7_10/bin/pythoncachedir: .cacherootdir: /home/user, inifile:collected 1 itemtest_fun.py::test_whatever xfail======================== 1 xfailed in 0.03 seconds=============================