如何模拟在不同命名空间中使用的类?

4

包结构:

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() 类以便测试 Ab 类的所有方法?


1
Python支持Monkey-Patching。您可以简单地调用pqr.pq.Lm = your_mockup,然后Ab将使用your_mockup而不是原始的Lm。(这回答了您的问题,但这可能不是最好的测试模式。考虑修改Ab的构造函数以允许传递替代Lm实现作为替代方案。) - Phillip
@Phillip,谢谢你的回答,但我没有完全理解,请给我一个可用的代码片段,我是测试框架的新手。 - Sanket
2个回答

8

无论 Lm 来自哪里都不重要。您将 Lm 导入到 pqr.pq 命名空间作为全局变量 there,因此您只需要在那里替换该名称,而不是其他任何地方。这是因为 Ab.__init__ 方法将在其自己的模块中 '本地' 查找它。

因此,使用mock,您只需要修补名称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部分


0

为了测试,您可以使用mock模块(在较新的Python 3中是标准的,在旧版本中可从pypi下载)来创建“虚假”类。有一篇关于mock库的很棒的文章,它解释了如何做到这一点,我会在这里提供链接,这对我帮助很大。您将希望您的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 模块,您可以创建一个模拟版本的模块/类,用于测试方法,只需在测试方法上方使用装饰器 "patch" 即可。这将使用 MagicMock 对象替换指定模块/类的原始版本,然后将其作为第二个参数传递到测试方法中。这个 MagicMock 不会实际执行 Lm 的任何功能,但允许您对其应该工作的方式进行断言。如果需要,您可以稍后覆盖功能。然而,有个小问题需要注意,在我提供的指南中有详细说明。您需要确保从使用它的模块中导入 Lm,而不是以传统方式导入。对于导入,Python 创建特定于导入模块的模块对象,因此您需要模拟来自 pq 模块的特定 Lm 对象才能测试其功能。这个库一开始使用可能有点复杂,并包含比单个 StackOverflow 答案涵盖的更多信息,所以我建议您进行一些阅读。

关于 mock 模块的文档可以在这里找到。 Python 2.7 版本的下载可在这里找到。

我对 mock 库也是刚接触,所以如果我有错误,请随意纠正!

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接