Как правильно утверждать, что исключение возникает в pytest?
код:
# coding=utf-8
import pytest
def whatever():
return 9/0
def test_whatever():
try:
whatever()
except ZeroDivisionError as exc:
pytest.fail(exc, pytrace=True)
Вывод:
================================ 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 ==============================
Как сделать трассировку печати pytest, поэтому я увижу, где в функции whatever
было создано исключение?
Ответы
Ответ 1
pytest.raises(Exception)
- это то, что вам нужно.
код
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
Выход
============================================================================================= 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 ======================================================================================
Обратите внимание, что e_info
сохраняет объект исключения, чтобы вы могли извлекать из него данные. Например, если вы хотите проверить стек вызовов исключений или другое вложенное исключение внутри.
Ответ 2
Вы имеете в виду что-то вроде этого:
def test_raises():
with pytest.raises(Exception) as excinfo:
raise Exception('some info')
assert excinfo.value.message == 'some info'
Ответ 3
Существует два способа обработки подобных случаев в pytest:
Использование pytest.raises
:
def whatever():
return 9/0
def test_whatever():
with pytest.raises(ZeroDivisionError):
whatever()
Использование pytest.mark.xfail
:
@pytest.mark.xfail(raises=ZeroDivisionError)
def test_whatever():
whatever()
Вывод 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
:
============================= 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=============================
Как сказано в документации:
Использование pytest.raises
, вероятно, будет лучше в тех случаях, когда вы тестируете исключения, которые ваш собственный код намеренно вызывает, тогда как использование @pytest.mark.xfail
с функцией проверки, вероятно, лучше для чего-то вроде документирования нефиксированных ошибок (где тест описывает, что "должно" случиться) или ошибки в зависимостях.
Ответ 4
вы можете попробовать
def test_exception():
with pytest.raises(Exception) as excinfo:
function_that_raises_exception()
assert str(excinfo.value) == 'some info'
Ответ 5
Это решение, которое мы используем:
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
Пожалуйста, обратитесь к pytest, https://docs.pytest.org/en/latest/reference.html#pytest-raises.
Ответ 6
Правильный способ использует pytest.raises
, но я нашел интересный альтернативный способ в комментариях здесь и хочет сохранить его для будущих читателей этого вопроса:
try:
thing_that_rasises_typeerror()
assert False
except TypeError:
assert True
Ответ 7
Pytest постоянно развивается, и с одним из приятных изменений в недавнем прошлом теперь можно одновременно тестировать на
- тип исключения (строгий тест)
- сообщение об ошибке (строгая или произвольная проверка с использованием регулярного выражения)
Два примера из документации:
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')
Я использовал этот подход в ряде проектов и мне очень нравится.
Ответ 8
Вы пытались удалить "pytrace = True"?
pytest.fail(exc, pytrace=True) # before
pytest.fail(exc) # after
Вы пытались работать с '--fulltrace'?
Ответ 9
Лучшая практика будет использовать класс, наследующий unittest.TestCase и запуск self.assertRaises.
Например:
import unittest
def whatever():
return 9/0
class TestWhatEver(unittest.TestCase):
def test_whatever():
with self.assertRaises(ZeroDivisionError):
whatever()
Затем вы выполните его, выполнив:
pytest -vs test_path