我怎样才能让pytest不捕获异常

How can I get pytest to not catch exceptions

当我在 运行 调试器中 运行 pytest 检查了“未捕获的异常”,并且有测试错误时,没有发生未捕获的异常,因为 pytest 捕获它们并进行结果报告。我如何告诉 pytest 让异常发生?以便我可以在 vscode 调试器中捕获它们?

基本上我想要像 --pdb 这样的行为,但我希望它启动 vscode 调试器而不是 pdb。标志 --pdbcls 听起来很有希望,但不确定 <module>:<class> 给它什么。

注意:通常我只会让它在出现异常时中断。但是我们的代码有大量引发但被捕获的异常,所以这个选项没有用。

这是一段 vscode 在调试 pytest 测试时引发 AssertionError 时没有中断的视频:

@rioV8 下面的建议确实打破了异常,但由于某种原因没有堆栈,这意味着你不能从那里调试:

我一定是遗漏了什么,因为似乎没有其他人需要此功能。但对我来说,这绝对是一个人可以用测试框架和调试器做的最基本的最简单的事情:作为一名开发人员,我想从出现错误的地方开始调试。

人们使用带有 pytest 的调试器一定有一些完全不同的方式,我忽略了一些明显的技术。

行为不相同,但测试运行程序在未捕获的异常处停止。

将文件 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 提出了 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 issuedebugpy,他们有一些想法,但今天没有解决方案。 _PYTEST_RAISE 技巧 100% 为我解决了这个问题。

我注意到一些可能相关的事情。尽管我现在还没有准备好深入挖掘,但我会 post 将它们放在这里,以防它们对某些人有用。

解决方法:

我使用的一个简单技巧是(暂时)直接调用相关测试用例,然后“运行 和调试”文件,而不是使用“调试测试用例”按钮:


def test_example():
    assert False


test_example()

结果:

备注:

  1. 行为的重要区别与在 launch.json 配置中指定 "request": "test" 与指定 "request": "launch" 相关。 (这两种类型之间的区别还在于 justMyCode 选项是否从全局启动配置中应用,如 here 所述)。
  2. 如果您指定了 python "request": "test",那么 VSCode 不会像我上面那样让您在启动模式下调试文件。
  3. 在我的场景中,由于我在第三方库中引起的异常(当然是我的错),我的测试失败了。第三方代码中的断点显然只有在添加 "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,
        // }        
    ]
}