如何在 python 单元测试中模拟未在本地安装的库?

How to mock in a python unittest a library not installed locally?

我正在尝试使用 unittest 以 (my_app.py):

开头的 python 3.6 脚本进行测试
import sys
from awsglue.utils import getResolvedOptions

args = getResolvedOptions(sys.argv, ['opt1', 'opt2', 'opt3'])
opt1 = args['opt1']
opt2 = args['opt2']
opt3 = args['opt3']
....

所以在我的测试中我做了类似的事情:

import unittest
import datetime
from mock import patch
import my_app

class TestMyApp(unittest.TestCase):

    @patch('awsglue.utils.getResolvedOptions')
    def test_mock_stubs(self, patch_opts):
        patch_opts.return_value = {}
        ....

但测试很快在 import my_app 失败,原因是:

ModuleNotFoundError: No module named 'awsglue'

因为没有 awsglue 本地安装。我如何测试导入非本地安装的库并在我的测试中模拟它的模块?

您需要在导入 my_app 之前模拟导入的模块。 patch 在这里不起作用,因为 patch 导入模块是为了修补它。在这种情况下,导入本身会导致错误。

要做到这一点,最简单的方法是让 python 认为 awsglue 已经被导入。您可以通过将模拟直接放在 sys.modules 字典中来做到这一点。在此之后,您可以执行 my_app 导入。

import unittest
import sys
from unittest import mock


class TestMyApp(unittest.TestCase):

    def test_mock_stubs(self):
        # mock the module
        mocked_awsglue = mock.MagicMock()
        # mock the import by hacking sys.modules
        sys.modules['awsglue.utils'] = mocked_awsglue
        mocked_awsglue.getResolvedOptions.return_value = {}

        # move the import here to make sure that the mocks are setup before it's imported
        import my_app

您可以将导入 hack 部分移动到 setup fixture 方法。

但是我建议只安装软件包。导入 hack 可能很难维护。