如何在 pytest 中断言 UserWarning 和 SystemExit

eve*_*007 8 python unit-testing systemexit user-warning pytest

在 pytest 中断言 UserWarning 和 SystemExit

在我的应用程序中,我有一个函数,当提供错误的参数值时,它将UserWarningswarnings模块引发,然后SystemExitsys模块引发。

代码是这样的:

def compare_tags(.....):

    requested_tags = user_requested_tags # as list
    all_tags = tags_calculated_from_input_file  # as list 

    non_matching_key = [x for x in requested_tags if x not in all_tags]

    # if user requested non existing tag then raise warning and then exit 
    if len(non_matching_key) > 0:

        # generate warning
        warnings.warn("The requested '%s' keys from '%s' is not present in the input file. Please makes sure the input file has the metadata of interest or remove the non matching keys." %(non_matching_key, given_tags))

        # raise system exit
        sys.exit(0)
Run Code Online (Sandbox Code Playgroud)

为上述函数编写 pytest

我想立即在 pytest 中UserWarning对此进行测试。我可以在 pytest 中SystemExit检查为。SystemExit

with pytest.raises(SystemExit):
    compare_tags(....)
Run Code Online (Sandbox Code Playgroud)

但这也会显示一条警告消息(这不是错误)。

如果我想检查警告:

pytest.warns(UserWarning, 
    compare_tags(...)
Run Code Online (Sandbox Code Playgroud)

这将产生SystemExit错误,因为调用的函数将触发系统退出。

如何将 和warningscheck放在SystemExit同一个 pytest 中?

hoe*_*ing 9

pytest.warns和是常见的上下文管理器,可以在用逗号分隔时pytest.raises在单个语句中声明(请参阅复合语句):with

with pytest.warns(UserWarning), pytest.raises(SystemExit):
    compare_tags(...)
Run Code Online (Sandbox Code Playgroud)

这实际上与写作相同

with pytest.warns(UserWarning):
    with pytest.raises(SystemExit):
        compare_tags(...)
Run Code Online (Sandbox Code Playgroud)

请注意,顺序很重要- 当您以相反的顺序放置两个上下文管理器时:

with pytest.raises(SystemExit), pytest.warns(UserWarning):
    ...
Run Code Online (Sandbox Code Playgroud)

这与写作相同

with pytest.raises(SystemExit):
    with pytest.warns(UserWarning):
        ...
Run Code Online (Sandbox Code Playgroud)

这里的问题是pytest.raises捕获所有引发的错误,然后检查捕获的内容。这包括pytest.warns引发的情况。这意味着

with pytest.raises(SystemExit), pytest.warns(UserWarning):
    sys.exit(0)
Run Code Online (Sandbox Code Playgroud)

会通过,因为 中提出的错误pytest.warns将被 吞没pytest.raises,而

with pytest.warns(UserWarning), pytest.raises(SystemExit):
    sys.exit(0)
Run Code Online (Sandbox Code Playgroud)

将按预期失败。