Search code examples
pythonunit-testingexceptiontestingpytest

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


Code:

# coding=utf-8
import pytest


def whatever():
    return 9/0

def test_whatever():
    try:
        whatever()
    except ZeroDivisionError as exc:
        pytest.fail(exc, pytrace=True)

Output:

================================ test session starts =================================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
plugins: django, cov
collected 1 items 

pytest_test.py F

====================================== FAILURES ======================================
___________________________________ test_whatever ____________________________________

    def test_whatever():
        try:
            whatever()
        except ZeroDivisionError as exc:
>           pytest.fail(exc, pytrace=True)
E           Failed: integer division or modulo by zero

pytest_test.py:12: Failed
============================== 1 failed in 1.16 seconds ==============================

How do I make pytest print traceback, so that I would see where in the whatever function that an exception was raised?


Solution

  • pytest.raises(Exception) is what you need.

    Code

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