如何从另一个测试脚本 运行 第一个脚本中模拟一个 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 的内容以供进一步参考。
我在单独的脚本 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 的内容以供进一步参考。