¿Cómo afirmar correctamente que una excepción se produce en pytest?

Código:

# coding=utf-8 import pytest def whatever(): return 9/0 def test_whatever(): try: whatever() except ZeroDivisionError as exc: pytest.fail(exc, pytrace=True) 

Salida:

 ================================ 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 ============================== 

¿Cómo hacer un seguimiento de la impresión en pytest, por lo que vería en qué función se generó una excepción?

pytest.raises(Exception) es lo que necesita.

Código

 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 

Salida

 ============================================================================================= 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 ====================================================================================== 

Tenga en cuenta que e_info guarda el objeto de excepción para que pueda extraer detalles de él. Por ejemplo, si desea comprobar la stack de llamadas de excepción u otra excepción anidada en el interior.

Te refieres a algo como esto:

 def test_raises(): with pytest.raises(Exception) as excinfo: raise Exception('some info') assert excinfo.value.message == 'some info' 

Hay dos formas de manejar este tipo de casos en pytest:

  • Usando la función pytest.raises

  • Usando el decorador pytest.mark.xfail

Uso de pytest.raises :

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

Uso de pytest.mark.xfail :

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

Salida de 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 ============================= 

Salida del marcador 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============================= 

Como dice la documentación :

Es probable que el uso de pytest.raises sea ​​mejor para los casos en los que está probando excepciones que su propio código está generando deliberadamente, mientras que el uso de @pytest.mark.xfail con una función de verificación es probablemente mejor para documentar errores no corregidos (donde la prueba describe qué “Debería” suceder) o errores en las dependencias.

puedes probar

 def test_exception(): with pytest.raises(Exception) as excinfo: function_that_raises_exception() assert str(excinfo.value) == 'some info' 

Esta solución es lo que estamos usando:

 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 

Consulte pytest, http://pytest.readthedocs.io/en/reorganize-docs/assert.html#assert

La forma correcta es usar pytest.raises pero encontré una forma alternativa interesante en los comentarios aquí y quiero guardarla para los futuros lectores de esta pregunta:

 try: thing_that_rasises_typeerror() assert False except TypeError: assert True 

¿Has intentado eliminar “pytrace = True”?

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

¿Has intentado correr con ‘–fulltrace’?

Una mejor práctica será usar una clase que herede unittest.TestCase y ejecutar self.assertRaises.

Por ejemplo:

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

Luego lo ejecutarías ejecutando:

 pytest -vs test_path