使用函数来模拟类方法的返回值

3

我是mock的新手,正在尝试使用side_effects。

我正在尝试基于调用该方法的参数设置模拟类的方法的返回值。在下面的代码中,当模拟MyClass时,我正在尝试设置some_function的返回值。

# application.py
from my_module.my_submodule import MyClass

def my_function(var1):
    instance = MyClass()

    instance.some_function(var1)

以及我的测试文件

# test_application.py
import mock
import application

def test_my_function():
    with mock.patch('application.MyClass') as MockClass:
        MockClass.return_value.my_function.return_value = some_return

        application.my_function(var1)

这段代码的作用是使some_function返回some_return,但我想要的是将some_return替换为一个函数,这个函数接收被调用时var1参数的值。
问题在于,我不知道如何定义模拟对象来预测some_function的调用参数。
我尝试了这篇帖子中讨论的内容changing the side effect of a mock object's method created with patch,但我无法弄清楚如何格式化它。
我的尝试代码如下:
# test_application.py
import mock
import application

def test_my_function():
    with mock.patch('application.MyClass') as MockClass:
        MockClass.return_value.my_function.return_value = some_return  

        # Breaking very long line, in my code it's actually one line.
        MockDataPrep.return_value.extract_preprocessed_citizen_data.\
        side_effect =\
        mock.MagicMock(side_effect=my_side_effect)

        application.my_function(var1)

其中函数my_side_effect的代码如下:

def my_side_effect(var1):
    return_val = some_manipulation_of_var1(var1)

    if something:
        return `abc`
    else:
        raise LookupError

但是似乎 my_side_effect 从未被执行过(已尝试在其中添加打印语句)。我该如何格式化它?

2个回答

3
你在嘲笑错误的方法。 my_functionapplication模块的函数,而不是MyClass的方法,因此你想要模拟的是some_function
import mock
import application


def my_side_effect(*args, **kwargs):
    print("my_side_effect called")
    print(args, kwargs)


def test_my_function():
    with mock.patch("application.MyClass") as MockClass:
        MockClass.return_value.some_function.side_effect = my_side_effect

        application.my_function(arg1)

通过这种方式,arg1 将被传递给 *args 中的 my_side_effect 方法。

此外,您可能只想模拟一个特定的方法,而不是整个类。

def test_my_function():
    with mock.patch("application.MyClass.some_function") as mock_some_function:
        mock_some_function.side_effect = my_side_effect

        application.my_function(arg1)

这真的帮了我很多:谢谢。我已经将您的答案链接到此处:https://dev59.com/bLXna4cB1Zd3GeqPFBu3#72617873 。如果您想在那里回答,我会删除我的链接/草图。 - scharfmn

0

看起来你使用了 side_effects,因为你无法使用 return_value

但是你可以使用 wraps 模拟参数。它将一个对象包装在一个 mock 中。你只能使用对象中已有的方法(虽然你可以添加更多),返回的结果是真实方法执行的结果。 return_value 将被忽略:

from unittest.mock import Mock

class Mirror:
    def func(self,x):
        return x

mirror = Mirror()
m = Mock(wraps=mirror)
print(m.func(20))

如果您想测试模拟对象的调用方式、参数、调用次数等信息,您可以使用模拟对象中的检查方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接