如何模拟:pytest.raises 没有加注 <class 'subprocess.TimeoutExpired'>

How to Mock: pytest.raises DID NOT RAISE <class 'subprocess.TimeoutExpired'>

我正在使用 subprocess 完成一项任务,并且我有一个 try/except 块用于捕获 TimeoutExpired。我尝试使用 side_effect 模拟我的对象,这样我就可以使用 pytest.raises 捕获假异常。无论我做什么,我都会得到 DID NOT RAISE <class 'subprocess.TimeoutExpired'>。 我已经尝试了很多东西,尽管我对模拟没有那么丰富的经验,但我相信这样的事情原则上应该可行:

# my_check.py
from subprocess import TimeoutExpired, PIPE, check_output

class Check:
    def __init__(self, name):
        self.name = name
        self.status = self.get_status()

    def get_status(self):
        try:
            out = check_output(["ls"], universal_newlines=True, stderr=PIPE, timeout=2)
        except TimeoutExpired as e:
            print(f"Command timed out: {e}")
            raise

        if self.name in out:
            return True
        return False


# test_my_check.py
import pytest
from unittest import mock
from subprocess import TimeoutExpired

@mock.patch("src.my_check.Check", autospec=True)
def test_is_installed_exception(check_fake):
    check_fake.get_status.side_effect = TimeoutExpired
    obj_fake = check_fake("random_file.txt")
    with pytest.raises(TimeoutExpired):
        obj_fake.get_status()

由于某种原因它不起作用,我无法理解哪里出了问题。

如果您想测试 class (Check) 的功能,您不能模拟 class。您必须模拟您想要更改的调用 - 在这种情况下可能 check_output,您想要引发异常:

@mock.patch("src.my_check.check_output")
def test_is_installed_exception(mocked_check_output):
    mocked_check_output.side_effect = TimeoutExpired("check_output", 1)
    with pytest.raises(TimeoutExpired):
        Check("random_file.txt")

一些注意事项:

  • 您必须修补“src.my_check.check_output”,因为您使用 from subprocess import check_output 导入 check_output,所以您使用 class
  • 中的引用
  • 您必须构造一个有效的 TimeoutExpired 对象 - 它需要 2 个参数,因此您必须提供它们
  • 由于 get_status 已在 __init__ 中调用,您必须测试 class 构造 - 由于引发的异常 [=26],您无法获得正确构造的实例=]