繁体   English   中英

如何使用补丁相对路径进行模拟?

[英]How to mock using patch relative paths?

我在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.pathPYTHONPATH情况下做到正确。

有什么指针吗?

从我收集到的,使用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 ab import c到你的包中给你一个简单的变量c ,所以这个机制应该有效。

我使用了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并通过monkey访问ook ,即monkey.ook 如果我需要经常写这个,我会在测试开始时添加ook = monkey.ook以方便起见。 (或者甚至是导入语句,以防我永远不需要模仿monkey这个特殊属性。)

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

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('')

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

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('')

当你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__来获取虚线包名,但是如果要从另一个模块进行修补,则需要拼写出来。

请记住,您导入的任何内容都可以从目标modulethatimports.nameimported

我认为这是因为你不进口monkey而是导入ook 如果您从..导入猴子,那么它应该工作。 否则,只需在ook上调用patch。

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

  • 根/
    • dumy /
      • 富/
        • module.py
    • dummy2 /
      • module2.py

您可以使用以下方法从module2.py导入module.py:

from root.dummy.foo import module

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM