如何从另一个测试脚本 运行 第一个脚本中模拟一个 class

How to mock a class in one script from another test script running the first

我在单独的脚本 sqles.py 中有一个 class SQLES,它在 main.py 中导入并包含读取 SQL 数据的方法并在 class 实例中设置结果。

我现在正在编写一个测试脚本,test_main.py,我想在其中定义一个模拟 SQLES class 以供 main.py 透明使用真正的 SQLES。我没有测试 SQLES 本身,模拟 class 的想法是包含相同的方法集,但 return 数据行的硬编码列表。

我已经搜索了几个小时,但 python/mock/etc 上没有一个结果解释了如何设置这个看似非常简单的要求。这是我目前准备的测试脚本(为清晰起见被截断):

import unittest.mock

import main    # main.py script I wish to run with the mocked SQLES class

class MockSQLES: # Dummy class I wish main.py to instantiate and use instead of SQLES

    def __init__(self):
        return

    def init(self, logger, cmd_args_record, cmd_args_playback):
        return

    # Couple of specimen methods, to give an idea of what dummy SQL class does ..

    def get_exchange_rates(self):
        self.exchange_rates['GBP'] = [
            [ '2021-09-13', 0.722298 ],
            [ '2021-08-20', 0.734203 ]
        ]
        return

    def get_firms_names_other(self):
         self.firms_names_other[firm_id] = [
            [ 131, 'Acme Industries' ],
            [ 132, 'Acme Research'   ]
        ]
        return

           ::::

with unittest.mock.patch('main.SQLES') as MockSQLES:

    main.main()

但是当我尝试 运行 它时,实例分配后的调试打印:

   sql = SQLES()

显示生成的 sql 对象的类型为 unittest.mock.MagicMock 而不是我预期的 MockSQLES,果然后者中的方法没有被调用。

总而言之,我想知道如何解决这个问题。也许 Mock 是错误的方法,其他一些方法(猴子补丁?)更适合这个。

此外,我不想对 main.py 脚本进行任何无法避免的修改。 (很明显,如果 main.py 有一个测试标志或类似的东西来创建 SQLES 或 MockSQL 的实例,那么如何使用 mock SQL class ES.)

您没有使用模拟 class。当您执行此操作时:

with unittest.mock.patch('main.SQLES') as MockSQLES:

上下文管理器 unittest.mock.patch 产生的响应将分配给 as clause 变量 MockSQLES。所以 MockSQLES 这里实际上不是模拟 class 而是补丁的产生响应。您可以尝试做的是:

with unittest.mock.patch('main.SQLES', MockSQLES) as mock_sql:

参考 unittest.mock.patch,第一个参数是修补 SQLES 的功能,而第二个参数是 MockSQLES 的替代功能,如文档所述:

unittest.mock.patch(target, new=DEFAULT, ...)

... the target is patched with a new object

确保还阅读有关 Mocking Classes 的内容以供进一步参考。