Python中如何为不同的MagicMock实例设置不同的属性?
How do you set different attributes for different MagicMock instances in Python?
我想断言 say_name
是用列表 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]
如果只创建了一个 MyClass
实例,通常情况下,我可以通过设置 mock_my_class.return_value = PropertyMock(name=name)
.
来设置属性
但是,在这种情况下,会创建 MyClass
的多个不同实例。
因此,此代码将引发错误,因为 my_func
由测试人员执行,say_name
正在传递一个没有 name
属性的模拟。
因此,如何为不同的MagicMock实例设置不同的属性?
可以使用 side_effect
从模拟中按顺序 return 值:
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['spam', 123, 'potato']
>>> m()
'spam'
>>> m()
123
>>> m()
'potato'
应用于您的用例:
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')]
我想断言 say_name
是用列表 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]
如果只创建了一个 MyClass
实例,通常情况下,我可以通过设置 mock_my_class.return_value = PropertyMock(name=name)
.
但是,在这种情况下,会创建 MyClass
的多个不同实例。
因此,此代码将引发错误,因为 my_func
由测试人员执行,say_name
正在传递一个没有 name
属性的模拟。
因此,如何为不同的MagicMock实例设置不同的属性?
可以使用 side_effect
从模拟中按顺序 return 值:
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['spam', 123, 'potato']
>>> m()
'spam'
>>> m()
123
>>> m()
'potato'
应用于您的用例:
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')]