Как правильно утверждать, что исключение возникает в 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

  • Использование pytest.mark.xfail decorator

Использование 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