如何模拟一个函数,该函数是从不同模块的导入方法中导入的 [英] 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
方法.
This function takes the name of a database, then builds a command string from it and executes this command as subprocess
with the execute_cmd
method.
I want to test this function without actually executing the subprocess
. I only want to check if the command is built correctly and correctly passed to execute_cmd
. Therefore I need to mock the execute_cmd
method which is imported from module utils
.
我的文件夹结构如下:
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
中尝试了以下操作:
So for my test I tried the following in 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
.因此,要验证是否使用了模拟返回值,请将其设置为1.7
.
但是未使用该函数的模拟程序,因为执行测试用例仍会产生1.6
,因为它正在执行应使用该模拟程序修补的实际函数.
The execution of the actual command yields 1.6
for Last Checkpoint
. So to verify if the mock return value is used, I set it to 1.7
.
But the mock for the function is not used, as the execution of the test case still yields 1.6
because it is executing the actual function that should have been patched with the mock.
知道我在这里错了吗?
推荐答案
您正在修补错误的位置.从 在何处修补部分:
You are patching the wrong location. From the Where to patch section:
patch()
的工作方式是(暂时)将名称指向的对象更改为另一个对象.可以有许多名称指向任何单个对象,因此,要使修补程序正常工作,必须确保对被测系统使用的名称进行修补.
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
作为全局变量,但是您没有修补该引用:
Your code-under-test finds execute_cmd
as a global in their own module, but you didn't patch that reference:
from ..utils import execute_cmd
已对my_package.utils.execute_cmd
引用进行了修补,但my_package.db_engine.db_functions
中的execute_cmd
引用仍将指向原始的未修补函数.
The my_package.utils.execute_cmd
reference is patched, but that execute_cmd
reference in my_package.db_engine.db_functions
will still point to the original, unpatched function.
改为修补导入的全局:
@patch('my_package.db_engine.db_functions.execute_cmd')
现在,在dbinfo
中的execute_cmd
查找将使用修补的模拟对象,而不是from ... import ...
语句所绑定的原始全局对象.
Now the execute_cmd
lookup inside dbinfo
will use the patched mock object rather than the original global bound by the from ... import ...
statement.
这篇关于如何模拟一个函数,该函数是从不同模块的导入方法中导入的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!