【问题标题】:How to assert call order and parameters when mocking multiple calls to the same method?模拟对同一方法的多次调用时如何断言调用顺序和参数?
【发布时间】:2016-10-20 00:27:41
【问题描述】:

我对同一个 mock 有多次调用,我想检查每个调用的参数和调用顺序。

例如如果我只需要检查最后一次通话,我会使用这个:

mock.assert_called_once_with(
    'GET',
    'https://www.foobar.com',
    params=OrderedDict([
        ('email', 'email'),
    ]),
    headers=None, 
    data=None)

但是我想为每次通话都这样做。

我已经做到了,就像这样:

mycode.py

from requests import Session

class Foo(object):

    def req(method, url, data, params=None, headers=None):
        self.session = Session()
        r = self.session.request(method, url, data=data, params=params, headers=headers)
        return r

test_mycode.py

@patch('myapp.mycode.Session')
def test_foobar(self, Session):
    # Set mock.
    self.request_mock = Session.return_value.request
    self.request_mock.return_value = MagicMock()

    data = {'foo': 'bar'}
    f = Foo()
    f.req('POST', 'https://www.foobar.com/', data=data)
    f.req('GET', 'https://www.foobar.com/', data=None)


    self.assertEqual(self.request_mock.call_count, 2)
    call1 = self.request_mock._mock_call_args_list[0]
    call2 = self.request_mock._mock_call_args_list[1]

    call_params = (
        ('POST', 'https://www.foobar.com'),
        {
            'headers': None,
            'allow_redirects': False,
            'params': None,
            'data': json.dumps(data)
        }
    )
    self.assertEqual(tuple(call1), call_params)

    call_params = (
        ('GET', 'https://www.foobar.com'),
        {
            'headers': None,
            'allow_redirects': False,
            'params': None,
            'data': None
        }
    )
    self.assertEqual(tuple(call2), call_params)

这可行,但我有点担心调用参数上的 assertEqual 方法。我觉得有更好的方法来做到这一点。我对嘲笑还是很陌生,所以任何建议都将不胜感激。

【问题讨论】:

    标签: python unit-testing mocking


    【解决方案1】:

    您可能想使用Mock.assert_has_calls 方法。

    self.assertEqual(self.request_mock.call_count, 2)
    self.request_mock.assert_has_calls([
        mock.call(
            'POST',
            'https://www.foobar.com',
            headers=None,
            allow_redirects=False,
            params=None,
            data=json.dumps(data)),
        mock.call(
            'GET',
            'https://www.foobar.com',
            headers=None,
            allow_redirects=False,
            params=None,
            data=None)
    ])
    

    默认情况下,assert_has_calls 将检查调用是否以正确的顺序发生。如果不关心顺序,可以使用any_order关键字参数(设置为True)。

    【讨论】:

    • 这对我不起作用,因为显然在 POST 和 GET 之间还有其他调用。 [call('POST', 'https://api.stormpath.com/v1/challenges/challenge_id', allow_redirects=False, data='{"code": "000000"}', headers=None, params=None), call().status_code.__eq__(301), E call().status_code.__eq__(302), E call().status_code.__ge__(400), E call().status_code.__le__(600), call('GET', 'https://api.stormpath.com/v1/challenges/challenge_id', allow_redirects=False, data=None, headers=None, params=None)],
    • @BoldMarshmallow 我认为您需要模拟更多的东西才能正确隔离您要测试的内容。
    • @BoldMarshmallow -- 另外,您实际上并没有展示您的真实代码。例如Foo.req 引用了从未定义过的 self。显然,其中的内容(可能在您的框架内)比您在此处显示的要多。
    • 是的,这是故意的。遗憾的是,出于隐私原因,我无法透露更多代码。 Ty 无论如何都要尝试。
    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    相关资源
    最近更新 更多