首页 > 解决方案 > 让 Pytest、Relative Import 和 Patch.Object 协同工作

问题描述

我在获取 pytest、相关导入和补丁以进行合作时遇到了麻烦。

我有以下内容:

from .. import cleanup

class CleanupTest(unittest.TestCase):

    @patch.object(cleanup, 'get_s3_url_components', MagicMock())
    @patch.object(cleanup, 'get_db_session', MagicMock(return_value={'bucket', 'key'}))
    @patch('time.time')
    def test_cleanup(self, mock_time, mock_session, mock_components):
        ...

我尝试了一些变化。

  1. 当前显示的一个。Pytest 返回“TypeError:test_cleanup() 正好需要 4 个参数(给定 2 个)”。它无法识别patch.objects,即使我很确定我根据https://docs.python.org/3/library/unittest.mock-examples.html正确使用它们
  2. 将 patch.objects 更改为简单的补丁会导致它们抛出“没有名为 cleanup 的模块”。我不知道如何使用带有相对导入的补丁。

编辑:我正在使用 Python 2.7,以防万一。

标签: pythonmockingpytest

解决方案


这实际上没有任何关系,pytest只是mock装饰者的行为

文档

如果 patch() 用作装饰器并被new省略,则创建的模拟作为额外参数传递给装饰函数

也就是说,因为您正在传递一个替换对象,所以不会发生签名突变

例如:

from unittest import mock

class x:
    def y(self):
        return 'q'

@mock.patch.object(x, 'y', mock.Mock(return_value='z'))
def t(x): ...


t()  # TypeError: t() missing 1 required positional argument: 'x'

幸运的是,如果你正在生成一个mock对象,你很少需要实际传递new参数并且可以使用关键字选项

对于您的特定示例,这应该可以正常工作:

    @patch.object(cleanup, 'get_s3_url_components')
    @patch.object(cleanup, 'get_db_session', return_value={'bucket', 'key'})
    @patch('time.time')
    def test_cleanup(self, mock_time, mock_session, mock_components): ...

如果你绝对需要它们是MagicMocks,你可以使用new_callable=MagicMock关键字参数


推荐阅读