28

我在 python 测试文件中有这样的东西:

from mock import patch,
from ..monkey import ook
[...]
@patch('monkey.ook', Mock(return_value=None))
def test_run_ook (self, mock_ook):
    self.assertIsNone(ook())
    mock_ook.run.assert_called_once_with('')

当我运行这个测试时,我得到一个ImportError: No module named monkey. 显然,我正在修补的路径不正确。sys.path但是,我不确定如何在不弄乱or的情况下使其正确PYTHONPATH

任何指针?

4

7 回答 7

25

我使用了 Dan Passaro 的解决方案,直到我遇到了这个使用patch.object- 这对我来说看起来更好:

from unittest.mock import patch,
from .. import monkey
[...]
@patch.object(monkey, 'ook', Mock(return_value=None))
def test_run_ook (self, mock_ook):
    self.assertIsNone(monkey.ook())
    mock_ook.run.assert_called_once_with('')

好处:

  • 不需要样板代码__name__ + '.object_to_be_mocked'
  • 测试用例的所有依赖项都在文件开头作为import语句明确说明。
  • 如果您尝试模拟的对象的虚线名称较长(例如“amazon.jungle.monkey.ook”)并且您因此编写@patch.object(amazon.jungle.monkey, 'ook', …),您的 IDE 的静态代码分析可以确保至少amazon.jungle.monkey是一个有效的变量因为你没有把整个事情写成一个字符串'amazon.jungle.monkey.ook'

缺点:

  • 你不能做from ..monkey import ook,但需要做from .. import monkey和访问ookmonkeymonkey.ook。在我需要经常写这个的情况下,ook = monkey.ook为了方便起见,我会在测试的开头添加。(或者甚至是 import 语句,以防我不需要模拟 . 的这个特定属性monkey。)
于 2014-05-24T11:48:19.247 回答
23

从我收集到的信息来看,使用 mock 时,您需要在修补时提供一个带点的名称。__name__幸运的是,每个模块都可以访问一个包含模块名称的特殊模块级变量。使用这个,如果你想修补你的模块的本地变量,你应该能够做如下的事情:

import mock
import unittest

ook = lambda: "the ook"


class OokTest(unittest.TestCase):

    def test_ook(self):
        with mock.patch(__name__ + '.ook', return_value=None):
            self.assertIsNone(ook())
        self.assertEquals(ook(), "the ook")

    # the patch decorator should work the same way, I just tend to use the
    # context manager out of personal preference
    @mock.patch(__name__ + '.ook', return_value=None)
    def test_ook_2(self, mock_ook):
        self.assertIsNone(ook())

假设您已将该文件保存为quicktest.py,则单元测试会给出以下结果:

$ python -m unittest quicktest
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

当然,在你的包中from a.b import c给你一个普通的变量c,所以同样的机制应该可以工作。

于 2013-06-26T15:56:04.760 回答
6

基于公认的答案,我相信这是实现预期目标的最干净的方法:

from mock import patch
from .. import monkey

@patch(monkey.__name__+'.ook', Mock(return_value=None))
def test_run_ook (self, mock_ook):
    self.assertIsNone(monkey.ook())
    mock_ook.run.assert_called_once_with('')
于 2015-11-30T10:54:46.900 回答
1

不确定这是否是最好的方法(甚至推荐),但一种方法是使用类似的方法:

from mock import patch,
from ..monkey import ook
[...]

package_base = __package__.rsplit('.', 1)[0]

@patch('{0}.monkey.ook'.format(package_base), Mock(return_value=None))
def test_run_ook (self, mock_ook):
    self.assertIsNone(ook())
    mock_ook.run.assert_called_once_with('')
于 2013-04-03T06:38:11.770 回答
1

当你from ..monkey import ook从一个模块中完成pkg1.pgk2.mymodule时,你最终得到的是pkg1.pgk2.mymodule.ook.

现在ook是在您执行from ... import .... 这就是您需要修补的目标。

所以你只需修补pkg1.pkg2.mymodule.ook

from unittest.mock import patch # mypackage.mymodule.patch
from ..monkey import ook        # mypacket.mymodule.ook

with patch("pkg1.pgk2.mymodule.ook"):
   ....

正如其他人所指出的,如果您从执行导入的同一模块进行修补,那么您可以使用__name__来获取带点的包名称,但如果您从另一个模块进行修补,则需要将其拼写出来。

请记住,您导入的任何内容都可以从 target 修补modulethatimports.nameimported

于 2015-09-24T13:12:30.790 回答
0

我认为这是因为您不 importmonkey而是 import ook。如果你从那里导入猴子,..它应该可以工作。否则,只需调用 patch on ook

于 2013-01-15T17:15:10.537 回答
-1

使用完整的导入路径。例如,如果你有这个文件系统:

  • 根/
    • 假人/
      • 富/
        • 模块.py
    • 假人2/
      • 模块2.py

您可以使用以下命令从 module2.py 导入 module.py:

from root.dummy.foo import module
于 2013-01-15T16:20:03.263 回答