在模拟中调用 python 内置字典

calling python builtin dict on a mock

我希望能够设置一个允许我在应用内置 dict 方法时 return 某些东西的模拟。

我试过使用 __iter__ 无济于事。除了一本空字典,我似乎什么也得不到:

import mock
mocked_object = mock.MagicMock()
mocked_object.__iter__.return_value = [1, 2, 3]
dict(mocked_object)
# {}

实际上我认为你需要做这样的事情:

mocked_object.keys.return_value.__iter__.return_value = [1, 2, 3]

有了这个,dict 方法将为您提供一个包含这些键的对象,以及 getattr(mocked_object, '1')(因此,另一个模拟方法)的结果作为值。如果您想对结果进行更多控制,我认为您也可以通过模拟 keys() 方法来做您想做的事。

来自 dict documentation

If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterable object. Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value.

MagicMock objects expose a keys method 只是因为是 mock objects 所以 dict() 会考虑它们 mapping对象。不幸的是,如果我们希望在 dict 上调用 mock 成为具有预定义键值的字典,那么这种方法使用起来有点复杂。以下示例显示如何通过使用 映射对象 协议实现 dict 到预定义字典的转换:

>>> m = MagicMock()
>>> d = {"a":"A", "b":"B", "c":"C"}
>>> m.keys.return_value.__iter__.return_value = ["a", "b", "c"]
>>> m.__getitem__.side_effect = ["A","B","C"]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
>>> #Little bit generic
>>> m.keys.return_value.__iter__.return_value = d.keys()
>>> m.__getitem__.side_effect = lambda k:d[k]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}

两者都有点难以阅读,在我们的测试中,我们希望阅读起来更简单。

要引导 dict 使用迭代器而不是映射,我们只需从 mock 中删除 keys 方法并设置 __iter__.return_value:

>>> del m.keys
>>> m.__iter__.return_value = [("a","A"),("b","B"),("c","C")]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
>>> #Little bit generic
>>> m.__iter__.return_value = d.items()
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}

恕我直言,这是设置模拟并从 dict 调用中获取预定义字典的一种简单而巧妙的方法。