pytest mocker.patch.object 的 return_value 使用与我传递的模拟不同的模拟

Chr*_*itz 3 python unit-testing mocking pytest python-unittest

我正在使用 pytest 修补 os.makedirs 方法以进行测试。在一个特定的测试中,我想添加异常的副作用。

因此,我导入os在测试脚本中导入的对象,对其进行修补,然后在测试中设置副作用:

from infrastructure.scripts.src.server_administrator import os

def mock_makedirs(self, mocker):
    mock = MagicMock()
    mocker.patch.object(os, "makedirs", return_value=mock)
    return mock

def test_if_directory_exist_exception_is_not_raised(self, administrator, mock_makedirs):
    mock_makedirs.side_effect = Exception("Directory already exists.")

    with pytest.raises(Exception) as exception:
        administrator.initialize_server()

    assert exception.value == "Directory already exists."
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,当在我的测试脚本中调用模拟时,副作用不再存在。在进行故障排除时,我停止了调试器中的测试,以查看我创建的模拟的 ID 值以及补丁应设置为返回值的模拟,发现它们是不同的实例:

在调试器中暂停并且 id 不匹配

我对 python 中的一些测试工具还比较陌生,所以这可能是我在文档中遗漏了一些东西,但是这里修补的返回的模拟不应该是我创建的模拟吗?难道是我补丁错了?

更新

我什至调整了导入样式以makedirs直接抓取来修补它:

def mock_makedirs(self, mocker):
    mock = MagicMock()
    mocker.patch("infrastructure.scripts.src.server_administrator.makedirs", return_value=mock)
    return mock

Run Code Online (Sandbox Code Playgroud)

我仍然遇到同样的“不同的模拟”问题。

Chr*_*itz 5

:捂脸:

我打补丁的方式不对。我正在考虑删除整个问题/答案,但我想我会把它留在这里,以防有人遇到同样的情况。

我这样定义补丁:

mocker.patch.object(os, "makedirs", return_value=mock)
Run Code Online (Sandbox Code Playgroud)

如果我将结果修补为 function/method ,这将是一个有效的结构。也就是说,这个补丁所说的是“当你调用makedirs 时,返回这个。

我真正想做的是返回一个模拟来代替该方法。在当前的形式中,我看到两个不同的模拟是有意义的,因为补丁逻辑当前是“用新的模拟替换 makedirs,然后当调用该模拟时,返回另一个模拟(我制作的模拟)”

我真正想要的只是:

mocker.patch.object(os, "makedirs", mock)
Run Code Online (Sandbox Code Playgroud)

我的第三个参数(以 patch.object 形式)是模拟模块参数(相对于命名return_value参数)。

回想起来,当我想到这一点时,这是非常明显的,这就是为什么我正在考虑删除这个问题,但这是一个很容易的错误,我现在将保留它。