如何模拟 class 在单独的命名空间中使用?

How to mock class used in separate namespace?

包结构:

pqr/pq.py
test.py

pqr/pq.py 具有以下结构

其中lmn是全局安装的pip模块

pq.py

的结构
from lmn import Lm

class Ab():

    def __init__(self):
        self.lm = Lm()

    def echo(self, msg):
        print msg

test.py 具有以下结构

from pqr.pq import Ab

如何在此处模拟 Lm() class 以便测试来自 Ab class 的所有方法?

Lm 来自哪里并不重要。您将 Lm 作为全局 那里 导入到 pqr.pq 命名空间中,因此您只能在那里替换该名称,而不是其他任何地方。那是因为 Ab.__init__ 方法会在它自己的模块中寻找它 'locally'。

所以使用 mock library 你需要做的就是修补名称 pqr.pq.Lm:

import mock
from pqr.pq import Ab

with mock.patch('pqr.pq.Lm') as mock_lm:
    # within this block, `Lm` in the `pqr.pq` namespace has been replaced
    # by a mock object
    test_instance = Ab()
    # assert that the patch succeeded; .return_value is used because
    # Ab.__init__ *calls* Lm()
    assert test_instance.lm is mock_lm.return_value

另请参阅 mock 文档的 Where to patch section

为了测试,您可以使用 mock 模块(较新的 python 3 中的标准模块,旧版本可从 pypi 下载)来创建 "fake" 类。模拟库上有一篇很棒的文章解释了如何做到这一点,我将 link here,这对我帮助很大。您希望 test.py 文件看起来像下面的代码。

from pqr import pq
import mock

class TestLm(unittest.Testcase):

    @mock.patch(pq.LM)
    def test_lm(self, mock_lm):
        my_ab = pq.AB()
        my_ab.echo()

使用 mock 模块,您可以创建一个 module/class 的模拟版本,您可以将其用于测试方法,只需 "patching" 在测试上方使用装饰器即可方法。这用 MagicMock 对象替换了指定 module/class 的原始版本,然后将其作为第二个参数传递给测试方法。这个 MagicMock 实际上并不执行 Lm 的任何功能,但允许您断言它应该如何工作。如果需要,您可以稍后覆盖功能。但是,有一个问题,在我 link 编辑的指南中对此进行了解释。您需要确保从使用它的模块导入 Lm ,而不是以传统方式。 对于导入,Python 创建模块对象特定于它们导入的模块,因此您需要从 pq 模块模拟特定的 Lm 对象以测试其功能。该库一开始使用起来有点复杂,并且包含的​​信息远远超过单个 Whosebug 答案中涵盖的信息,因此我建议您阅读一些内容。

可以找到 mock 模块的文档 here。 Python 2.7 版本的下载可以在 here.

找到

我自己对 mock 库还很陌生,如果我错了,请随时纠正我!

编辑:看到 Martijn 的回答后,我意识到我忘记了 my_ab 构造函数中的括号!