如何正确地断言在pytest中引发exception?

码:

# 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打印回溯,所以我会看到在whateverfunctionexception提出的地方?

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保存exception对象,以便可以从中提取详细信息。 例如,如果你想检查exception调用堆栈或其他嵌套的exception里面。

你的意思是这样的:

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

你可以试试

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

在pytest中有两种方法来处理这种情况:

  • 使用pytest.raises函数

  • 使用pytest.mark.xfail修饰符

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/ukpdl, 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/ukpdl, inifile: collected 1 item test_fun.py::test_whatever xfail ======================== 1 xfailed in 0.03 seconds============================= 

正如文件所说:

使用pytest.raises可能会更好,因为你正在testing你自己的代码故意提高的exception,而使用@pytest.mark.xfail和check函数可能更适合于像logging未@pytest.mark.xfail错误(testing描述了什么“应该”发生)或错误的依赖。

你有没有尝试删除“pytrace = True”?

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

你有没有试图用' – fulltrace'来运行?

更好的做法是使用inheritanceunittest.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