from mock import MagicMock, call
m = MagicMock()
m.foo()
for i in m:
print m
m.bar()
print m.mock_calls
[call.foo(), call.__iter__(), call.bar()]
[call.foo(), call.__iter__(), call.bar()] == m.mock_calls
False
如何断言在一系列调用中迭代了一个模拟对象?如果我将__iter__.return_value
设置为其他内容,也会发生同样的事情。
答案 0 :(得分:2)
一个有效但难看的解决方案是[call.foo(), ('__iter__', (), {}), call.bar()] == m.mock_calls
。
答案 1 :(得分:1)
潜在的问题是mock.call
返回mock._Call
的实例,而tuple
本身是__iter__
的子类。作为一个元组,它继承了元组的('__iter__', (), {})
方法,并且您正在获取该实际方法,而不是像往常一样动态捕获属性访问以产生链式调用。
可以说,比在呼叫清单中对call.__getattr__('__iter__')()
进行硬编码更好的一种可能的解决方法是改为>>> mock.call.__getattr__('__iter__')() == ('__iter__', (), {})
True
,其效果大致相同:
getattr(mock.call, '__iter__')
(请注意,您无法执行tuple.__iter__
,因为这只会再次为您提供实际的mock._Call
方法)
或者,您可以继承__iter__
的子类,并自己构建call
的行为较好的版本(至少相对于class _IterCall(mock._Call):
def __getattr__(self, attr):
if self._mock_name is None:
return type(self)(name=attr, from_kall=False)
name = '%s.%s' % (self._mock_name, attr)
return type(self)(name=name, parent=self, from_kall=False)
def __iter__(self):
return self.__getattr__('__iter__')()
iter_call = _IterCall(from_kall=True)
而言):
__getattr__
(它也必须覆盖mock._Call.__getattr__
,因为mock._Call
的实现将显式地返回原始type(self)
类的实例,而不是>>> iter_call.__iter__() == ('__iter__', (), {})
True
)
import requests
import pandas as pd
url = 'https://stats.nba.com/stats/leaguedashplayerstats'
payload = {
'College': '',
'Conference': '',
'Country': '',
'DateFrom': '',
'DateTo': '',
'Division': '',
'DraftPick': '',
'DraftYear': '',
'GameScope': '',
'GameSegment': '',
'Height': '',
'LastNGames': '0',
'LeagueID': '00',
'Location': '',
'MeasureType': 'Base',
'Month': '0',
'OpponentTeamID': '0',
'Outcome': '',
'PORound': '0',
'PaceAdjust': 'N',
'PerMode': 'PerGame',
'Period': '0',
'PlayerExperience':'' ,
'PlayerPosition': '',
'PlusMinus': 'N',
'Rank': 'N',
'Season': '2019-20',
'SeasonSegment': '',
'SeasonType': 'Regular Season',
'ShotClockRange': '',
'StarterBench': '',
'TeamID': '0',
'TwoWay': '0',
'VsConference': '',
'VsDivision':'' ,
'Weight': ''}
jsonData = requests.get(url, params=payload).json()
cols = jsonData['resultSets'][0]['headers']
rows = jsonData['resultSets'][0]['rowSet']
df = pd.DataFrame(rows, columns=cols)
两种方法都有缺点。
答案 2 :(得分:0)
如果调用了模拟对象,则其called
属性为True
:
>>> m = MagicMock()
>>> assert m.__iter__.called, "The object was not iterated over"
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
builtins.AssertionError: The object was not iterated over
>>> for i in m:
... print(m)
...
>>> assert m.__iter__.called, "The object was not iterated over"
>>> m.__iter__.called
True
在这种情况下,m.__iter__
也是一个模拟,它是“按需”创建的(作为访问__iter__
方法的结果)。
答案 3 :(得分:0)
我尝试避免猜测正确的语法,因此我写了helper library来根据实际调用为我生成断言。
如果在代码末尾添加以下行:
import mock_autogen.generator
print(mock_autogen.generator.generate_asserts(m))
您会得到:
m.foo.assert_called_once_with()
m.__iter__.assert_called_once_with()
m.bar.assert_called_once_with()
因此,您不再需要自己找出确切的语法,只需应用该工具即可:)