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

2024-04-20 09:16:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我在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的情况下使它正确。

有什么线索吗?


Tags: 文件runfromimportselfnone内容return
3条回答

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

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

据我所知,使用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在包中给了您一个简单的变量,所以同样的机制也应该起作用。

我使用了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。(甚至是import语句,以防我不需要模拟monkey的这个特殊属性。)

相关问题 更多 >