How to properly assert that an exception gets raised in pytest?
1 2 3 4 5 6 7 8 9 10 11 12 | # coding=utf-8 import pytest def whatever(): return 9/0 def test_whatever(): try: whatever() except ZeroDivisionError as exc: pytest.fail(exc, pytrace=True) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ================================ 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打印回溯,所以我会看到在
码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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 |
产量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ============================================================================================= 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 ====================================================================================== |
请注意,
您的意思是这样的吗:
1 2 3 4 5 6 | def test_raises(): with pytest.raises(Exception) as excinfo: raise Exception('some info') # these asserts are identical; you can use either one assert execinfo.value.args[0] == 'some info' assert str(execinfo.value) == 'some info' |
有两种方法可以在pytest中处理此类情况:
-
使用
pytest.raises 函数 -
使用
pytest.mark.xfail 装饰器
1 2 3 4 5 | def whatever(): return 9/0 def test_whatever(): with pytest.raises(ZeroDivisionError): whatever() |
1 2 3 | @pytest.mark.xfail(raises=ZeroDivisionError) def test_whatever(): whatever() |
1 2 3 4 5 6 7 8 9 10 11 | ============================= 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 ============================= |
1 2 3 4 5 6 7 8 9 10 | ============================= 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============================= |
如文档所述:
Using
pytest.raises is likely to be better for cases where you are testing exceptions your own code is deliberately raising, whereas using@pytest.mark.xfail with a check function is probably better for something like documenting unfixed bugs (where the test describes what"should" happen) or bugs in dependencies.
你可以试试
1 2 3 4 | def test_exception(): with pytest.raises(Exception) as excinfo: function_that_raises_exception() assert str(excinfo.value) == 'some info' |
pytest不断发展,并且随着最近的一次重大变化,现在可以同时测试
- 异常类型(严格测试)
- 错误消息(使用正则表达式进行严格检查或宽松检查)
文档中的两个示例:
1 2 | with pytest.raises(ValueError, match='must be 0 or None'): raise ValueError('value must be 0 or None') |
1 2 | with pytest.raises(ValueError, match=r'must be \d+$'): raise ValueError('value must be 42') |
我已经在许多项目中使用了这种方法,并且非常喜欢它。
正确的方法是使用
1 2 3 4 5 | try: thing_that_rasises_typeerror() assert False except TypeError: assert True |
该解决方案是我们正在使用的解决方案:
1 2 3 4 5 6 7 | 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
更好的做法是使用继承unittest.TestCase并运行self.assertRaises的类。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 | import unittest def whatever(): return 9/0 class TestWhatEver(unittest.TestCase): def test_whatever(): with self.assertRaises(ZeroDivisionError): whatever() |
然后,您可以通过运行以下命令来执行它:
1 | pytest -vs test_path |
您是否尝试删除" pytrace = True"?
1 2 | pytest.fail(exc, pytrace=True) # before pytest.fail(exc) # after |
您是否尝试过使用'--fulltrace'吗?