How to correctly state that an exception occurs in pytest?

the 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 to make a print trace for pytest, so I will see where an exception was thrown in whatever function?

+206
python unit-testing testing pytest
Apr 28 '14 at 9:33
source share
9 answers

pytest.raises(Exception) is what you need.

the 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 

Exit

 ============================================================================================= 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 that you can retrieve data from it. For example, if you want to check the exception call stack or another nested exception inside.

+229
Apr 24 '15 at 18:52
source share

You mean something like this:

 def test_raises(): with pytest.raises(Exception) as excinfo: raise Exception('some info') assert excinfo.value.message == 'some info' 
+97
May 7 '14 at 10:10
source share

There are two ways to handle such cases in pytest:

  • Using the pytest.raises function

  • Using pytest.mark.xfail decorator

Using pytest.raises :

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

Using pytest.mark.xfail :

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

The 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/python cachedir: .cache rootdir: /home/user, inifile: collected 1 item test_fun.py::test_whatever PASSED ======================== 1 passed in 0.01 seconds ============================= 

pytest.xfail marker pytest.xfail :

 ============================= 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/python cachedir: .cache rootdir: /home/user, inifile: collected 1 item test_fun.py::test_whatever xfail ======================== 1 xfailed in 0.03 seconds============================= 

As the documentation says:

Using pytest.raises is likely to be better when you test the exceptions that your own code intentionally raises, while using @pytest.mark.xfail with a validation function is probably better for something like documenting unfixed errors ( where the test describes what “should” happen) or errors in dependencies.

+44
Nov 15 '17 at 13:20
source share

you can try

 def test_exception(): with pytest.raises(Exception) as excinfo: function_that_raises_exception() assert str(excinfo.value) == 'some info' 
+35
May 24 '17 at 16:24
source share

This is the solution we use:

 def test_date_invalidformat(): """ Test if input incorrect data will raises ValueError exception """ date = "06/21/2018 00:00:00" with pytest.raises(ValueError): app.func(date) #my function to be tested 

Please refer to pytest, https://docs.pytest.org/en/latest/reference.html#pytest-raises.

+4
Jun 25 '18 at 2:47
source share

The correct way is using pytest.raises , but I found an interesting alternative way in the comments here and want to keep it for future readers of this question:

 try: thing_that_rasises_typeerror() assert False except TypeError: assert True 
+4
Aug 22 '18 at 4:55
source share

Pytest is constantly evolving, and with one of the nice changes in the recent past, you can now test simultaneously on

  • exception type (strict test)
  • error message (strict or arbitrary validation using a regular expression)

Two examples from the documentation:

 with pytest.raises(ValueError, match='must be 0 or None'): raise ValueError('value must be 0 or None') 
 with pytest.raises(ValueError, match=r'must be \d+$'): raise ValueError('value must be 42') 

I used this approach in a number of projects and I really like it.

+1
Jun 12 '19 at
source share

Have you tried to remove "pytrace = True"?

 pytest.fail(exc, pytrace=True) # before pytest.fail(exc) # after 

Have you tried working with '--fulltrace'?

0
Feb 11 '16 at 13:57
source share

Best practice would be to use a class that inherits unittest.TestCase and run self.assertRaises.

For example:

 import unittest def whatever(): return 9/0 class TestWhatEver(unittest.TestCase): def test_whatever(): with self.assertRaises(ZeroDivisionError): whatever() 

Then you execute it by doing:

 pytest -vs test_path 
0
Jan 02 '17 at 14:22
source share



All Articles