首页 > 解决方案 > 在单个测试中禁用 pytest 警告捕获

问题描述

我通常喜欢 pytest 警告捕获钩子,因为我可以使用它来强制我的测试套件不触发任何警告。但是,我有一项测试需要将警告正确打印到 stderr 才能正常工作。

如何仅针对一项测试禁用警告捕获?

例如,像

def test_warning():
    mystderr = StringIO()
    sys.stderr = mystderr
    warnings.warn('warning')
    assert 'UserWarning: warning' in mystderr.getvalue()

(我知道我可以使用capsys,我只是想展示基本思想)

标签: pythonpytest

解决方案


由于这次讨论的范围缩小,我认为这个问题最好标题为“在 pytest 中,如何在单个测试中捕获警告及其标准错误输出?”。鉴于建议的改写,我认为答案是“它不能,你需要一个单独的测试”。

如果没有标准错误捕获要求,您应该能够为此使用@pytest.mark.filterwarnings注释。

@pytest.mark.filterwarnings("ignore")
def test_one():
    assert api_v1() == 1

来自: https ://docs.pytest.org/en/latest/warnings.html#pytest-mark-filterwarnings

@wim 在评论中指出,尽管如此,这不会捕获警告,并且他列出的答案以标准方式捕获并断言警告。

如果有 stderr 输出但没有抛出 Python 警告,则 capsys 将是该技术,正如您所说的 https://docs.pytest.org/en/latest/capture.html

由于 pytest 实现的性质,我认为在 pytest 测试中同时执行这两种操作没有意义。

如前所述,pytest 将 stderr 等重定向到内部记录器。其次,它定义了自己的警告处理程序 https://github.com/pytest-dev/pytest/blob/master/src/_pytest/warnings.py#L59

它的想法与这个问题的答案相似: https ://stackoverflow.com/a/5645133/5729872

我对 redefining 进行了一些warnings.showwarning()探讨,它在 vanilla python 上运行良好,但 pytest 也故意重新初始化它。

不能在 pytest 中工作,只能直接使用 python -->

def func(x):
    warnings.warn('wwarn')
    print(warnings.showwarning.__doc__)
    # print('ewarn', file=sys.stderr)
    return x + 1

sworig = warnings.showwarning

def showwarning_wrapper(message, category, filename, lineno, file=None, line=None):
    """Local override for showwarning()"""
    print('swwrapper({})'.format(file) )
    sworig(message,category,filename,lineno,file,line)

warnings.showwarning = showwarning_wrapper

<-- 不能在 pytest 中工作,只能在 python 中工作

您可能可以在您的测试用例中放置一个警告处理程序,该处理程序重新输出到 stderr ......但这并不能证明测试中的代码,在这一点上。

归根结底,它是您的系统。如果在考虑了@wim 提出的关于测试 stderr 本身可能证明不多的观点之后,您决定仍然需要它,我建议将 Python 警告对象(python 调用者层)的测试与 stderr 的内容(调用 shell层)。第一个测试将只查看 Python 警告对象。新的第二个测试用例将通过或类似的方式将被测库作为脚本调用popen(),并对产生的标准错误和输出进行断言。


推荐阅读