首页 > 解决方案 > 使用 python、pytest、mock 在另一个模块中模拟第 3 方函数

问题描述

我有一个正在生产中且无法修改的函数 func1()。它调用另一个模块中的函数function_to_be_mocked()。这需要输入参数。

我有另一个调用 func1() 的函数 func2()。

我正在编写单元测试来测试 func2(),并尝试模拟 function_to_be_mocked(因为它取决于我在本地系统上没有(也不应该拥有)的一些键)。我唯一可以修改的是 test_func2()。

我有如下设置(最小示例):

from othermodule import function_to_be_mocked
import pytest
import mock

def func1():
    function_to_be_mocked(None)

def func2():
    ret = func1()
    print (ret)

@mock.patch('othermodule.function_to_be_mocked', return_value = 3)
def test_func2(mocker):
    func2()

而 othermodule.py 是:

def function_to_be_mocked(arg1):
    if not arg1 == 'foo':
        raise ValueError

我的输出:

直接调用func2:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/blah/temp.py", line 9, in func2
    ret = func1()
  File "/Users/blah/temp.py", line 6, in func1
    function_to_be_mocked(None)
  File "/Users/blah/othermodule.py", line 3, in function_to_be_mocked
    raise ValueError
ValueError

调用我希望被嘲笑的 test_func2() :

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/blah/venv/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/Users/blah/temp.py", line 14, in test_func2
    func2()
  File "/Users/blah/temp.py", line 9, in func2
    ret = func1()
  File "/Users/blah/temp.py", line 6, in func1
    function_to_be_mocked(None)
  File "/Users/blah/othermodule.py", line 3, in function_to_be_mocked
    raise ValueError
ValueError

所以模拟似乎不起作用。有没有人有任何想法如何实现这一目标?

============ 在此行下方编辑 ============

听起来我不能做我认为可以做的事情(因为我实际上无法修改与功能 1 或 2 相关的任何内容。我所能控制的只是测试。

让我提出以下问题,因为也许比我更有经验的眼睛可以看到前进的方向。

我有一个功能:

def function_to_be_tested(args):
    # Some processing steps

    # Function call that works locally
    function_that_returns_something_1()

    # Some logic

    # Function call that works locally
    function_that_returns_something_2()

    # Function that raises an exception when running locally,
    # and since I need to test the logic after this function 
    # (and cannot edit this code here to bypass it) I would 
    # (naively) like to mock it.
    function_I_would_like_to_mock()

    # Much more logic that follows this function. 
    # And this logic needs to be unit tested.
    return some_value_based_on_the_logic

测试:

def test_function_to_be_tested():
    assert function_to_be_tested(args) == some_expected_value

我可以在 function_I_would_like_to_mock() 之前轻松地对任何东西进行单元测试。

但是由于这个函数在本地崩溃(我无法编辑代码来阻止它在本地崩溃),我觉得正确的方法是模拟它并强制一个合理的返回值。这样我就可以对除此之外的代码路径进行单元测试。

你会建议什么作为一个好方法?

请注意,我唯一可以修改的是测试功能。我什至无法将装饰器添加到主要功能中。

标签: pythonunit-testingmockingpytest

解决方案


选项 A)

您愿意模拟的函数被加载到 func1 中。因此,您必须将 @patch 装饰器应用于 func1

import pytest
from unittest import mock

@mock.patch('othermodule.function_to_be_mocked', return_value = 3)
def func1(mocker):
    from othermodule import function_to_be_mocked
    function_to_be_mocked(None)

def func2():
    ret = func1()
    print (ret)

def test_func2():
    func2()

test_func2()

=========编辑===========

选项 B)

import pytest
from unittest import mock


def func1():
    from othermodule import function_to_be_mocked
    function_to_be_mocked(None)

def func2():
    ret = func1()
    print (ret)

def test_func2():
    with mock.patch('othermodule.function_to_be_mocked', return_value = 3) as irrelevant:
        func2()

test_func2()

推荐阅读