Python Mock Patch 为被测子模块和被测子模块中的每个其他导入子模块打补丁

Python Mock Patch patches a used module for submodule under test and every other imported submodule in the submodule under test

抱歉,标题有点混乱,但很难找到清晰的标题。

我的问题:

我有一个正在测试的子模块,我们称它为 backend。我在 backend 中使用 random.choice。我在我的测试中对其进行了修补并且有效。它已打补丁。 backend 导入 pymongo 来做一些数据库工作,pymongo 也使用 random.choicecore.py.

中选择正确的服务器

不知何故,我的 backend.random.choice 补丁也被用于 backend.pymongo.random.choice。我不确定为什么。这是正确的行为吗?如果是,有什么方法可以解决这个问题?最好不要更改后端和 pymongo 中的任何代码,但仅在我的测试中。

其他调查:

我设置了一个小测试结构,看看它是否与我的项目相关或一般情况。

我创建了一些模块:

bar/bar.py

import random

def do_some_other_something():
    return random.choice([10])

foo/foo.py

import random
from bar.bar import do_some_other_something

def do_something():
    return random.choice([1])

def do_something_else():
    return do_some_other_something()

还有一个测试用例:

from foo.foo import do_something, do_something_else
from unittest import mock

assert(do_something() == 1) # check
assert(do_something_else() == 10) # check

with mock.patch("foo.foo.random.choice") as mock_random_choice:
    assert (do_something() != 1) # check (mocked as expected)
    assert (do_something_else() == 10) # assertion! also mocked

所以我对此真的很困惑。我明确地嘲笑了 foo.foo 的 random.choice 而不是 bar.bar 的。那为什么会这样呢?故意的?有办法解决这个问题吗?

谢谢!

程序中只有一个 random 模块。当 foo.foobar.barimport random 时,它们 共享 random 模块。在 random 模块上修补 choice 函数会修改程序每个部分使用的一个 random 模块,包括 foo.foobar.bar.

不是修补 foo.foo.random.choice,而是修补 foo.foo.random。这会替换 foo.foorandom 模块的引用,但不会替换 bar.bar 的引用。 bar.bar 将继续访问真正的 random 模块,但 foo.foo 将看到模拟 random.