Python Mock Patch为测试中的子模块和被测子模块中的每个其他导入的子模块修补一个用过的模块

时间:2018-02-03 02:44:15

标签: python unit-testing monkeypatching

对于相当令人困惑的标题感到抱歉,但发现很难获得一个清晰的标题。

我的问题:

我有一个正在测试的子模块,可以调用它backend。我在random.choice中使用backend。我在我的测试中修补它,这是有效的。它是补丁。 backend导入pymongo以执行某些数据库操作,pymongo也使用random.choice来选择core.py中的正确服务器。

我的backend.random.choice补丁也用于backend.pymongo.random.choice。我不知道为什么。这是正确的行为吗?如果是,那么解决这个问题的方法是什么?优先不改变后端和pymongo中的任何代码,但仅限于我的测试。

其他调查:

我设置了一个小测试构造,看看这是否与我的项目或一般事物有关。

我创建了一些模块:

酒吧/ bar.py

import random

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

富/ 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' s。那为什么会这样呢?意?有办法解决这个问题吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

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

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