在单个测试中禁用pytest警告捕获

时间:2019-06-04 03:00:06

标签: python pytest

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

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

例如,类似

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

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

2 个答案:

答案 0 :(得分:1)

由于本次讨论的范围有所缩小,我认为这个问题最好命名为“在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

我在重新定义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()或类似名称将被测试的库作为脚本调用,并对所产生的标准错误和输出进行断言。

答案 1 :(得分:-1)

我鼓励您以不同的方式考虑这个问题。

如果要断言某些代码会触发警告,则应使用pytest.warns上下文。使用match kwarg检查警告消息,避免尝试从stderr捕获警告消息带来的额外麻烦。

import re
import warnings

import pytest

def test_warning():
    expected_warning_message = "my warning"
    match = re.escape(expected_warning_message)
    with pytest.warns(UserWarning, match=match):
        warnings.warn("my warning", UserWarning)

这应该是测试职责的边缘。测试警告本身导致某些输出输出到stderr上,这不是您的责任,因为该行为来自标准库代码和它应该由Python本身进行测试。