如何让 pytest 不捕获异常
Posted
技术标签:
【中文标题】如何让 pytest 不捕获异常【英文标题】:How can I get pytest to not catch exceptions 【发布时间】:2020-10-06 17:46:38 【问题描述】:当我在 vscode 调试器中运行 pytest 并选中“未捕获的异常”,并且有测试错误时,不会发生未捕获的异常,因为 pytest 捕获它们并进行结果报告。我如何告诉 pytest 让异常发生?以便我可以在 vscode 调试器中捕获它们?
基本上我想要--pdb
这样的行为,但我希望它启动 vscode 调试器而不是 pdb。标志--pdbcls
听起来很有希望,但不确定<module>:<class>
应该给它什么。
注意:通常我只会让它在引发异常时中断。但是我们的代码有大量引发但捕获的异常,所以这个选项没有用。
这是一段在调试 pytest 测试时触发 AssertionError 时 vscode 没有中断的视频:
@rioV8 下面的建议确实打破了异常,但由于某种原因没有堆栈,这意味着您无法从那里进行调试:
我一定是遗漏了一些东西,因为似乎没有其他人需要这种能力。但对我来说,这似乎绝对是使用测试框架和调试器可以做的最基本最简单的事情:作为开发人员,我想从引发错误的地方开始调试。
人们在使用带有 pytest 的调试器时一定有一些完全不同的方式,我忽略了一些明显的技术。
【问题讨论】:
它对我来说很好用,因为你给出了任何代码 sn-p 我只能猜测。如果您在测试中使用了with pytest.raises
,那么您实际上已经捕获了异常,因此调试器不会中断
它对你来说很好,因为 pytest 本身退出时出现异常?我怀疑除非你以某种方式安排它,因为通常 pytest 会捕获异常,以便它可以在运行结束时报告哪些测试失败。您不同意 pytest 通常会捕获所有异常以便报告测试失败吗?
如果我没有with pytest.raises
,它确实会崩溃
我们没有使用pytest.raises
,它不会中断。我正在使用TEST:PYTHON
树视图中测试右侧的Debug
按钮运行。它会在Python Test Log
输出窗格中打印异常的名称,但不会中断。如果我在调试器中检查 Raised Exceptions 它将中断,但我不能这样做,因为有太多误报,我们引发和捕获的不相关异常。如果 vscode 允许您选择要中断的异常,那将有很大帮助。
我在原始问题中添加了一个视频,展示了 vscode 如何不会对我造成破坏。
【参考方案1】:
我用 pytest 提出了an issue,他们提出了一个可行的建议。将此添加到您的conftest.py
:
import os
import pytest
if os.getenv('_PYTEST_RAISE', "0") != "0":
@pytest.hookimpl(tryfirst=True)
def pytest_exception_interact(call):
raise call.excinfo.value
@pytest.hookimpl(tryfirst=True)
def pytest_internalerror(excinfo):
raise excinfo.value
然后在您的"request": "test"
launch.json 中,您可以切换该环境变量:
"name": "Debug Tests",
"type": "python",
"request": "test",
"console": "integratedTerminal",
"justMyCode": true,
"env":
"_PYTEST_RAISE": "1"
,
如果设置了_PYTEST_RAISE
,并且您只选中了未捕获的异常框,那么您将在未捕获异常之前出现的地方中断。
我还打开了an issue 和debugpy
,他们有一些想法,但今天没有解决方案。 _PYTEST_RAISE
技巧 100% 为我解决了这个问题。
【讨论】:
【参考方案2】:行为不一样,但测试运行程序在未捕获的异常处停止。
将文件 conftest.py
添加到包含您的测试的目录中。
# conftest.py
def pytest_exception_interact(node, call, report):
print( call.excinfo.traceback[0] )
pass
这为任何未捕获的异常添加了一个钩子。
在pass
所在的行放置一个断点。
然后Debug
测试。
查看调试控制台,您会看到发生异常的文件和行号。
test_example.py F File 'path\\test_example.py':4 in test_example
assert False
调试器停在pass
行。
你可以把这个钩子函数做成你喜欢的样子。
【讨论】:
谢谢,我可以试试这个。但是我很难理解 pytest 如何没有标志或模式。希望调试器在您的测试失败的地方中断似乎是世界上最自然的事情。人们一般如何调试测试? 我试过这个。它确实在那里中断,但没有堆栈,因此不能用于调试。我把图片和cmets放在原来的问题里。 我认为他们正在努力解决这个问题:github.com/microsoft/debugpy/issues/275 @Philip : 然后在调试控制台显示的行添加一个断点并重试 是的,可以运行 pytest,在控制台中查看异常发生的位置,在代码中找到该位置,然后在它引发之前在那里放置一个断点。我不认为这是这个问题的答案或非常好的解决方案。但是是的,它在紧要关头起作用,我一直在这样做。【参考方案3】:我注意到一些可能相关的事情。尽管我现在还没有准备好深入挖掘,但我会将它们发布在这里,以防它们对某人有用。
解决方法:
我使用的一个简单技巧是直接(临时)调用相关的测试用例并“运行和调试”文件,而不是使用“调试测试用例”按钮:
def test_example():
assert False
test_example()
结果:
注意事项:
-
行为的重要区别与在
launch.json
配置中指定"request": "test"
与指定"request": "launch"
相关。 (两种类型之间的区别在于 justMyCode
选项是否从全局启动配置中应用,如 here 所述)。
如果您指定了 python "request": "test"
,那么 VSCode 似乎不允许您像我在上面所做的那样在启动模式下调试文件。
在我的场景中,我的测试失败了,因为我在第三方库中引发了异常(当然是我的错)。第三方代码中的断点显然只有在添加 "justMyCode": false
选项时才会触发。
launch.json:
"version": "0.2.0",
"configurations": [
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "$file",
"console": "integratedTerminal",
"justMyCode": false,
,
//
// "name": "Debug Unit Test",
// "type": "python",
// "request": "test",
// "console": "integratedTerminal",
// "justMyCode": false,
//
]
【讨论】:
以上是关于如何让 pytest 不捕获异常的主要内容,如果未能解决你的问题,请参考以下文章