如何提取存储在 mock.call 中的参数

How to extract parameters stored in mock.call

我正在对以下功能进行单元测试:

import uuid


def process_name(id, name, weight):
    print('process_item:', id, name, weight)


def process_list(names):
    for (name, weight) in names:
        id = uuid.uuid4()
    process_name(id, name, weight)

我的单元测试如下所示:

import unittest
from mock import patch, call
import SomePackage.SomeModule


class MyTestCase(unittest.TestCase):
    def test_something(self):
        items = [('Joe', 190), ('Dan', 200)]
        with patch('SomePackage.SomeModule.process_name') as mock_process_name:
            SomePackage.SomeModule.process_list(items)

我无法匹配整个 mock_calls 东西,因为提交给它的第一个参数是一个 guid,因此每次调用函数时它都会不同:

print(mock_process_name.mock_calls)
[call(UUID('some randomish guid'), 'Joe', 190),
 call(UUID('some other guid'), 'Dan', 200)]

我要提取参数,只匹配非易失性参数:

 print(mock_process_name.mock_calls[0][1][1:])
 print(mock_process_name.mock_calls[1][1][1:])
 ('Joe', 190)
 ('Dan', 200)

我知道我也可以模拟 returns guid 的东西,并在它的 side_effect 中提供一个固定的值列表。但是,我觉得很懒惰需要模拟太多东西,比如 uuid.uuid4()datetime.now() 等等。这就是为什么我正在寻找一种替代方法来模拟每个 volatile 函数。

是否有比 mock_calls[0][1][1:] 更具可读性的替代方案?

有人提议在某处支持此用例(错误或模拟回购?)但据我所知,它尚未实施。

现在您可以按照我的喜好顺序选择这些选项:

检查你需要什么

assert "Joe" in xx.mock_calls[0][1]
assert 190 in xx.mock_calls[0][1]

还有一个好处是,当测试失败时,您可以确切地知道这两个测试中的哪个失败了。

模拟 UUID

用可预测的顺序模拟它,然后你就可以验证你的调用了。

使用mock.ANY

xx.assert_called_with(mock.ANY, "Dan", 200)

遗憾的是,仅适用于最后一次调用。 你可以分解你的测试。

assert_any_call

xx.assert_any_call(mock.ANY, "Joe", 190)

但是您无法验证 Joe 和 Dan 的相对顺序。

mock.ANY 迂回

assert xx.mock_calls[0][1] == (mock.ANY, "Joe", 190)

进行断言的最简单方法是

mock_process_name.assert_has_calls([call(ANY, "Dan", 200), call(ANY, "Joe", 190)])

其中 ANY 是从 mock 模块

导入的助手

如果您对调用顺序不感兴趣,可以使用 any_order=True 选项。此外,如果您的连锁调用很复杂,您可以查看 Tracking order of calls and less verbose call assertions.