0

我想断言它say_name是用 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]

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

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

因此,此代码将引发错误,因为my_func它是由测试人员执行的,say_name并且正在传递一个没有name属性的模拟。

那么,如何为不同的 MagicMock 实例设置不同的属性呢?

4

1 回答 1

2

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

>>> 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')]
于 2018-07-31T18:04:31.917 回答