在 Pytest 中重构测试逻辑以避免复杂的 Raises 块

Refactoring Test Logic in Pytest to Avoid Complex Raises Block

我正在使用 flake8-pytest-style 插件,它会将某个测试标记为违反 PT012。这是关于 raises() 语句中的逻辑过多。

有问题的代码是这样的:

def test_bad_python_version(capsys) -> None:
    import platform
    from quendor.__main__ import main

    with pytest.raises(SystemExit) as pytest_wrapped_e, mock.patch.object(
        platform,
        "python_version",
    ) as v_info:
        v_info.return_value = "3.5"
        main()
        terminal_text = capsys.readouterr()
        expect(terminal_text.err).to(contain("Quendor requires Python 3.7"))

    expect(pytest_wrapped_e.type).to(equal(SystemExit))
    expect(pytest_wrapped_e.value.code).to(equal(1))

基本上这是在测试以下代码:

def main() -> int:
    if platform.python_version() < "3.7":
        sys.stderr.write("\nQuendor requires Python 3.7 or later.\n")
        sys.stderr.write(f"Your current version is {platform.python_version()}\n\n")
        sys.exit(1)

我所做的只是传递一个低于要求的 Python 版本,并确保错误按预期出现。测试本身工作得很好。 (我意识到这是否应该是一个单元测试可能值得怀疑,因为它实际上更多地测试了 Python 的一个方面,而不是我自己的代码。)

很明显,lint 检查表明我的测试有点混乱,我当然可以理解。但是从上面引用的页面中我不清楚我应该怎么做。

我确实意识到我可以只禁用此特定测试的质量检查,但我正在尝试尽可能地编写 Python 代码,尤其是围绕测试。我不知道如何重构此代码以满足标准。

我知道我可以创建一些其他测试辅助函数,然后从 raises 块中调用该函数。但这让我觉得总体上不太清楚,因为现在你必须在两个地方查看才能看到测试在做什么。

lint 错误非常好!事实上在你的情况下因为没有遵循 lint 错误你有两行无法访问的代码(!)(两个 capsys 相关的行)因为 main() 总是引发

lint 提示您 raises() 块中只有一行 -- 您现有代码的原始重构是:

    with mock.patch.object(
        platform,
        "python_version",
        return_value="3.5",
    ):
        with pytest.raises(SystemExit) as pytest_wrapped_e:
            main()

    terminal_text = capsys.readouterr()
    expect(terminal_text.err).to(contain("Quendor requires Python 3.7"))

    expect(pytest_wrapped_e.type).to(equal(SystemExit))
    expect(pytest_wrapped_e.value.code).to(equal(1))

另外,您永远不应该使用 platform.python_version() 进行版本比较,因为它会为 python 3.10 生成不正确的结果 -- more on that and a linter for it here