如何检索对模拟的调用的所有内容?

End*_*der 6 python unit-testing mocking pytest

我正在为一个函数编写单元测试,该函数采用字典数组并最终将其保存在 CSV 中。我试图像往常一样用 pytest 模拟它:

csv_output = (
    "Name\tSurname\r\n"
    "Eve\tFirst\r\n"
)
with patch("builtins.open", mock_open()) as m:
    export_csv_func(array_of_dicts)

assert m.assert_called_once_with('myfile.csv', 'wb') is None
[and here I want to gather all output sent to the mock "m" and assert it against "csv_output"]
Run Code Online (Sandbox Code Playgroud)

我无法以任何简单的方式获取在open()阶段发送到模拟的所有数据来进行批量比较,而不是逐行进行比较。为了简化事情,我验证了以下代码模拟了对模拟执行的操作:csvexport_csv_func()

with patch("builtins.open", mock_open()) as m:
  with open("myfile.csv", "wb") as f:
    f.write("Name\tSurname\r\n")
    f.write("Eve\tFirst\r\n")
Run Code Online (Sandbox Code Playgroud)

当我深入模拟时,我看到:

>>> m
<MagicMock name='open' spec='builtin_function_or_method' id='4380173840'>
>>> m.mock_calls
[call('myfile.csv', 'wb'),
 call().__enter__(),
 call().write('Name\tSurname\r\n'),
 call().write('Eve\tFirst\r\n'),
 call().__exit__(None, None, None)]
>>> m().write.mock_calls
[call('Name\tSurname\r\n'), call('Eve\tFirst\r\n')]
>>> dir(m().write.mock_calls[0])
['__add__'...(many methods), '_mock_from_kall', '_mock_name', '_mock_parent', 'call_list', 'count', 'index']
Run Code Online (Sandbox Code Playgroud)

我在 MagickMock 界面中看不到任何可以收集模拟已收到的所有输入的内容。

我也尝试调用,m().write.call_args但它只返回最后一个调用(mock_calls属性的最后一个元素,即call('Eve\tFirst\r\n'))。

有什么办法可以做我想做的事吗?

who*_*ski 6

您可以创建自己的mock.call对象并将它们与.call_args_list.

from unittest.mock import patch, mock_open, call

with patch("builtins.open", mock_open()) as m:
    with open("myfile.csv", "wb") as f:
        f.write("Name\tSurname\r\n")
        f.write("Eve\tFirst\r\n")

# Create your array of expected strings
expected_strings = ["Name\tSurname\r\n", "Eve\tFirst\r\n"]
write_calls = m().write.call_args_list
for expected_str in expected_strings:
    # assert that a mock.call(expected_str) exists in the write calls
    assert call(expected_str) in write_calls
Run Code Online (Sandbox Code Playgroud)

请注意,您可以使用您选择的断言调用。如果您在 unittest.TestCase 子类中,则更喜欢使用self.assertIn.

此外,如果您只想要 arg 值,您可以将mock.call对象解包为元组。索引 0 是 *args。例如:

for write_call in write_calls:
    print('args: {}'.format(write_call[0]))
    print('kwargs: {}'.format(write_call[1]))
Run Code Online (Sandbox Code Playgroud)