如何模拟一个函数,该函数是从不同模块的导入方法中导入的 [英] How to mock a function, that is imported within an imported method from different module

查看:92
本文介绍了如何模拟一个函数,该函数是从不同模块的导入方法中导入的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要测试以下功能:

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 Checkpoint1.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆