在 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
我正在使用 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