如何在 Python 中为不同的 MagicMock 实例设置不同的属性? [英] How do you set different attributes for different MagicMock instances in Python?

查看:28
本文介绍了如何在 Python 中为不同的 MagicMock 实例设置不同的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想断言 say_name 是用列表 name 中的每个值调用的.

from unittest.mock 导入补丁类我的类:def __init__(self, name):self.name = 姓名def say_name(name):print('我的名字是' + 姓名)def my_func():名称 = ['foo', 'bar', 'baz']objects = [MyClass(name) for name in names][对象中对象的say_name(object.name)]@patch('my_test.say_name', spec_set=True)@patch('my_test.MyClass', spec_set=True)def test_my_func(mock_my_class, mock_say_name):名称 = ['foo', 'bar', 'baz']my_func()[mock_my_class.assert_any_call(name) for name in names]# [mock_say_name.assert_any_call(x.name) for x in xs]

如果只创建了一个 MyClass 实例,通常情况下,我可以通过设置 mock_my_class.return_value = PropertyMock(name=name) 来设置属性.

但是,在这种情况下,会创建 MyClass 的多个不同实例.

因此,此代码将抛出错误,因为 my_func 由测试人员执行,say_name 正在传递一个没有 name 属性的模拟.

因此,如何为不同的 MagicMock 实例设置不同的属性?

解决方案

可以使用 side_effect 从模拟中顺序返回值:

<预><代码>>>>从 unittest.mock 导入 Mock>>>m = 模拟()>>>m.side_effect = ['垃圾邮件', 123, '马铃薯']>>>米()'垃圾邮件'>>>米()123>>>米()'土豆'

应用于您的用例:

from types import SimpleNamespace从 unittest.mock 导入调用,补丁从 my_lib 导入 my_func@patch('my_lib.say_name')@patch('my_lib.MyClass')def test_my_func(mock_my_class, mock_say_name):FakeObj 类:经过obj1 = FakeObj()obj1.name = 'foo'obj2 = FakeObj()obj2.name = 'bar'obj3 = FakeObj()obj3.name = 'baz'mock_my_class.side_effect = [obj1, obj2, obj3]my_func()assert mock_my_class.call_args_list == [call('foo'), call('bar'), call('baz')]assert mock_say_name.call_args_list == [call('foo'), call('bar'), call('baz')]

I'd like to assert that say_name was called with each value in the list name.

from unittest.mock import patch


class MyClass:
    def __init__(self, name):
        self.name = name


def say_name(name):
    print('My name is ' + name)


def my_func():
    names = ['foo', 'bar', 'baz']
    objects = [MyClass(name) for name in names]
    [say_name(object.name) for object in objects]


@patch('my_test.say_name', spec_set=True)
@patch('my_test.MyClass', spec_set=True)
def test_my_func(mock_my_class, mock_say_name):
    names = ['foo', 'bar', 'baz']
    my_func()
    [mock_my_class.assert_any_call(name) for name in names]
    # [mock_say_name.assert_any_call(x.name) for x in xs]

If only one instance of MyClass was created, as is usually the case, I could set the attribute by setting mock_my_class.return_value = PropertyMock(name=name).

However, in this case, multiple different instances of MyClass are created.

Thus, this code will throw an error because my_func is executed by the tester, say_name is being passed a mock with no name attribute.

Therefore, how can I set different attributes for different MagicMock instances?

解决方案

It is possible to use side_effect to sequentially return values from a mock:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['spam', 123, 'potato']
>>> m()
'spam'
>>> m()
123
>>> m()
'potato'

Applying to your use-case:

from types import SimpleNamespace
from unittest.mock import call, patch

from my_lib import my_func


@patch('my_lib.say_name')
@patch('my_lib.MyClass')
def test_my_func(mock_my_class, mock_say_name):

    class FakeObj:
        pass

    obj1 = FakeObj()
    obj1.name = 'foo'
    obj2 = FakeObj()
    obj2.name = 'bar'
    obj3 = FakeObj()
    obj3.name = 'baz'

    mock_my_class.side_effect = [obj1, obj2, obj3]
    my_func()
    assert mock_my_class.call_args_list == [call('foo'), call('bar'), call('baz')]
    assert mock_say_name.call_args_list == [call('foo'), call('bar'), call('baz')]

这篇关于如何在 Python 中为不同的 MagicMock 实例设置不同的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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