Иногда, при тестировании кода необходимо убедится, что заложенные в коде приложения ожидаемые исключения появляются именно в ожидаемых ситуациях. Фреймворк pytest
дает такую возможность по средствам использования контекстного менеджера pytest.raises(Exc, match=None)
.
Exc
: объект исключения Exception
или кортеж объектов Exception
;Аргумент match
: если указано, то это строка, содержащая регулярное выражение или объект регулярного выражения, который проверяется на соответствие строковому представлению исключения с помощью re.search()
. Может содержать специальные символы, шаблон может быть сначала экранирован с помощью re.escape()
.
Аргумент match
используется только тогда, когда pytest.raises()
используется в качестве диспетчера контекста. При использовании pytest.raises()
в качестве функции можно использовать: pytest.warns(Exc, func, match="passed on").match("my pattern")
Например:
import pytest def test_zero_division(): with pytest.raises(ZeroDivisionError): 1 / 0
Если нужно получить доступ к фактической информации об исключении, то можно использовать экземпляр класса ExceptionInfo
:
def test_recursion_depth(): with pytest.raises(RuntimeError) as excinfo: def f(): f() f() assert "maximum recursion" in str(excinfo.value)
Переменная excinfo
- это ни что иное как экземпляр класса ExceptionInfo
, которым обертывается вызванное исключение. Наиболее интересными его атрибутами являются ExceptionInfo.type
, ExceptionInfo.value
и ExceptionInfo.traceback
.
Чтобы проверить, что строковому представлению исключения (аналогично методу TestCase.assertRaisesRegexp
модуля unittest
) соответствует регулярное выражение, то менеджеру контекста можно передать параметр match
:
import pytest def myfunc(): raise ValueError("Exception 123 raised") def test_match(): with pytest.raises(ValueError, match=r".* 123 .*"): myfunc()
Регулярное выражение аргумента match
сопоставляется с функцией re.search
, так что в приведенном выше примере match='123'
также сработает.
Есть и альтернативный вариант использования pytest.raises()
, когда передается функция, которая которая должна выполняться с заданными *args
и **kwargs
и проверять, что вызвано указанное исключение:
pytest.raises(ExpectedException, func, *args, **kwargs)
В случае падения теста, pytest
выведет полезную информацию, например, о том, что исключение не вызвано (no exception
) или вызвано неверное исключение (wrong exception
).
Обратите внимание, что декоратор @pytest.mark.xfail()
также принимает аргумент raises
, который особым образом проверяет само падение теста, а не просто возникновение какого-то исключения:
@pytest.mark.xfail(raises=IndexError) def test_f(): f()
Использование функции pytest.raises()
скорее всего пригодится, когда тестируются исключения, генерируемые собственным кодом, а применение декоратора @pytest.mark.xfail()
для тестовой функции, лучше подойдет для документирования незафиксированных (когда тест описывает то, что "должно бы" происходить) или зависимых от чего-либо падений кода.