Питон глумиться список аргументов вызова распаковка кортежей для утверждения на аргументы
У меня возникли некоторые проблемы с вложенным кортежем, который Mock.call_args_list
возвращает.
def test_foo(self):
def foo(fn):
fn('PASS and some other stuff')
f = Mock()
foo(f)
foo(f)
foo(f)
for call in f.call_args_list:
for args in call:
for arg in args:
self.assertTrue(arg.startswith('PASS'))
Я хотел бы знать, есть ли лучший способ распаковать этот call_args_list на макет объекта, чтобы сделать мое утверждение. Эта петля работает, но кажется, что должен быть более прямой путь вперед.
2 ответа:
Я думаю, что многие из трудностей здесь связаны с обработкой объекта "вызов". Его можно рассматривать как кортеж с 2 членами
(args, kwargs)
, и поэтому часто приятно распаковать его:args, kwargs = call
Как только он распакован, вы можете сделать свои утверждения отдельно для args и kwargs (так как один является кортежем, а другой-диктом)
def test_foo(self): def foo(fn): fn('PASS and some other stuff') f = Mock() foo(f) foo(f) foo(f) for call in f.call_args_list: args, kwargs = call self.assertTrue(all(a.startswith('PASS') for a in args))
Обратите внимание, что иногда краткость не помогает (например, если есть ошибка):
for call in f.call_args_list: args, kwargs = call for a in args: self.assertTrue(a.startswith('PASS'), msg="%s doesn't start with PASS" % a)
Более приятным способом может быть создание ожидаемых вызовов вашего "я", а затем использование прямого утверждения:
Обратите внимание, что вызовы должны быть последовательными, если вы не хотите этого, то переопределите>>> from mock import call, Mock >>> f = Mock() >>> f('first call') <Mock name='mock()' id='31270416'> >>> f('second call') <Mock name='mock()' id='31270416'> >>> expected_calls = [call(s + ' call') for s in ('first', 'second')] >>> f.assert_has_calls(expected_calls)
any_order
kwarg для утверждения.Также обратите внимание, что допускается наличие дополнительных вызовов до или после указанные вызовы. Если вы этого не хотите, вам нужно добавить еще одно утверждение:
>>> assert f.call_count == len(expected_calls)
Обращаясь к комментарию mgilson, вот пример создания манекена объект, который можно использовать для сравнения равенства подстановочных знаков:
>>> class AnySuffix(object): ... def __eq__(self, other): ... try: ... return other.startswith('PASS') ... except Exception: ... return False ... >>> f = Mock() >>> f('PASS and some other stuff') <Mock name='mock()' id='28717456'> >>> f('PASS more stuff') <Mock name='mock()' id='28717456'> >>> f("PASS blah blah don't care") <Mock name='mock()' id='28717456'> >>> expected_calls = [call(AnySuffix())]*3 >>> f.assert_has_calls(expected_calls)
И пример режима отказа:
>>> Mock().assert_has_calls(expected_calls) AssertionError: Calls not found. Expected: [call(<__main__.AnySuffix object at 0x1f6d750>), call(<__main__.AnySuffix object at 0x1f6d750>), call(<__main__.AnySuffix object at 0x1f6d750>)] Actual: []