如何使用Mock修补导入模块的'open'函数

2 投票
1 回答
1359 浏览
提问于 2025-04-17 19:59

我正在为我写的一个模块编写单元测试。我需要对 open 进行修补,这样当被测试模块里的函数调用 open 时,就会使用一个模拟的版本,而不是实际的 open

这段代码可以正常工作,但我觉得它可能会影响其他测试,因为它没有把 open 恢复到原来的状态:

class TestCases(unittest.TestCase):
    def test_something(self):
        from amodule import bmodule

        open_mock = mock.MagicMock(spec=open)
        bmodule.__builtins__['open'] = open_mock
        read_mock = mock.MagicMock()
        open_mock.return_value.__enter__.return_value = read_mock

        self.assertTrue(bmodule.some_function())
        self.assertEqual(open_mock.call_args_list, ['filename1', 'filename2'])

我该如何使用 mock.patch 来做到这一点呢?

1 个回答

4

与其在 __builtins__ 中修改 open 函数,不如直接在 bmodule 里进行修改。这样做的好处是,只有 bmodule 中的函数会使用你修改后的 open 函数。

你可以在 mock 文档 中看到更多详细信息。

你可以通过使用 patch.object 作为上下文管理器来替换你的 open 函数:

from mock import patch
class TestCases(unittest.TestCase):
    def test_something(self):
        from amodule import bmodule

        open_mock = mock.MagicMock(spec=open)
        read_mock = mock.MagicMock()
        open_mock.return_value.__enter__.return_value = read_mock
        with patch.object(bmodule, 'open', open_mock, create=True):
            self.assertTrue(bmodule.some_function())
        self.assertEqual(open_mock.call_args_list, ['filename1', 'filename2'])

使用 with 语句可以保证,当执行离开 with 块时,修改会被移除。create=True 这个部分是为了让 patch 知道你确实想在 bmodule 的命名空间中创建 open 的绑定。这是一个安全措施,防止人们不小心修改错误的名称,但在你的情况下,这是必要的,因为 open__builtins__ 中,而你想把它绑定到 bmodule 中。

撰写回答