如何模拟在不同模块的导入方法中导入的函数
How to mock a function, that is imported within an imported method from different module
我有以下功能要测试:
my_package.db_engine.db_functions.py:
from ..utils import execute_cmd
from my_package.db_engine.db_functions import dbinfo
def dbinfo(db_name):
params = (cmd_cfg.DB, add_pj_suffix(db_name))
cmd = get_db_cmd_string(cmd_cfg.DBINFO, params=params)
cmd_result = execute_cmd(cmd)
result_dict = map_cmd_output_to_dict(cmd_result)
return result_dict
此函数获取数据库的名称,然后从中构建命令字符串并使用 execute_cmd
方法将此命令作为 subprocess
执行。
我想在不实际执行 subprocess
的情况下测试此功能。我只想检查命令是否正确构建并正确传递给 execute_cmd
。因此我需要模拟从模块 utils
.
导入的 execute_cmd
方法
我的文件夹结构如下:
my_project
|_src
| |_my_package
| | |_db_engine
| | | |_db_functions.py
| | | |_ __init__.py
| | |_utils.py
| | |_ __init__.py
| | |_ ....
| |_ __init__.py
|_tests
|_test_db_engine.py
因此,为了我的测试,我在 test_db_engine.py
中尝试了以下操作:
import unittest
from mock import patch
from my_pacakge.db_engine.db_functions import dbinfo
def execute_db_info_cmd_mock():
return {
'Last Checkpoint': '1.7',
'Last Checkpoint Date': 'May 20, 2015 10:07:41 AM'
}
class DBEngineTestSuite(unittest.TestCase):
""" Tests für DB Engine"""
@patch('my_package.utils.execute_cmd')
def test_dbinfo(self, test_patch):
test_patch.return_value = execute_db_info_cmd_mock()
db_info = dbinfo('MyDBNameHere')
self.assertEqual(sandbox_info['Last Checkpoint'], '1.7')
实际命令的执行为 Last Checkpoint
产生 1.6
。因此,为了验证是否使用了 mock return 值,我将其设置为 1.7
。
但是没有使用该函数的模拟,因为测试用例的执行仍然会产生 1.6
因为它正在执行应该用模拟修补的实际函数。
知道我在这里错了什么吗?
您打错了位置。来自 Where to patch section:
patch()
works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.
The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
您的测试代码发现 execute_cmd
在它们自己的模块中是全局的,但您没有修补该引用:
from ..utils import execute_cmd
my_package.utils.execute_cmd
引用已修补,但 my_package.db_engine.db_functions
中的 execute_cmd
引用仍将指向未修补的原始函数。
改为修补导入的全局:
@patch('my_package.db_engine.db_functions.execute_cmd')
现在 dbinfo
中的 execute_cmd
查找将使用修补后的模拟对象,而不是 from ... import ...
语句绑定的原始全局对象。
我有以下功能要测试:
my_package.db_engine.db_functions.py:
from ..utils import execute_cmd
from my_package.db_engine.db_functions import dbinfo
def dbinfo(db_name):
params = (cmd_cfg.DB, add_pj_suffix(db_name))
cmd = get_db_cmd_string(cmd_cfg.DBINFO, params=params)
cmd_result = execute_cmd(cmd)
result_dict = map_cmd_output_to_dict(cmd_result)
return result_dict
此函数获取数据库的名称,然后从中构建命令字符串并使用 execute_cmd
方法将此命令作为 subprocess
执行。
我想在不实际执行 subprocess
的情况下测试此功能。我只想检查命令是否正确构建并正确传递给 execute_cmd
。因此我需要模拟从模块 utils
.
execute_cmd
方法
我的文件夹结构如下:
my_project
|_src
| |_my_package
| | |_db_engine
| | | |_db_functions.py
| | | |_ __init__.py
| | |_utils.py
| | |_ __init__.py
| | |_ ....
| |_ __init__.py
|_tests
|_test_db_engine.py
因此,为了我的测试,我在 test_db_engine.py
中尝试了以下操作:
import unittest
from mock import patch
from my_pacakge.db_engine.db_functions import dbinfo
def execute_db_info_cmd_mock():
return {
'Last Checkpoint': '1.7',
'Last Checkpoint Date': 'May 20, 2015 10:07:41 AM'
}
class DBEngineTestSuite(unittest.TestCase):
""" Tests für DB Engine"""
@patch('my_package.utils.execute_cmd')
def test_dbinfo(self, test_patch):
test_patch.return_value = execute_db_info_cmd_mock()
db_info = dbinfo('MyDBNameHere')
self.assertEqual(sandbox_info['Last Checkpoint'], '1.7')
实际命令的执行为 Last Checkpoint
产生 1.6
。因此,为了验证是否使用了 mock return 值,我将其设置为 1.7
。
但是没有使用该函数的模拟,因为测试用例的执行仍然会产生 1.6
因为它正在执行应该用模拟修补的实际函数。
知道我在这里错了什么吗?
您打错了位置。来自 Where to patch section:
patch()
works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
您的测试代码发现 execute_cmd
在它们自己的模块中是全局的,但您没有修补该引用:
from ..utils import execute_cmd
my_package.utils.execute_cmd
引用已修补,但 my_package.db_engine.db_functions
中的 execute_cmd
引用仍将指向未修补的原始函数。
改为修补导入的全局:
@patch('my_package.db_engine.db_functions.execute_cmd')
现在 dbinfo
中的 execute_cmd
查找将使用修补后的模拟对象,而不是 from ... import ...
语句绑定的原始全局对象。