如何模拟 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 构造函数中的括号!
包结构:
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 构造函数中的括号!