#python #mocking
#python #издевательство
Вопрос:
В assert_called_once_with
, как я могу указать параметр «любой экземпляр класса Foo»?
Например:
class Foo(): pass
def f(x): pass
def g(): f(Foo())
import __main__
from unittest import mock
mock.ANY
конечно, проходит:
with mock.patch.object(__main__, 'f') as mock_f:
g()
mock_f.assert_called_once_with(mock.ANY)
и, конечно, другой экземпляр Foo не проходит.
with mock.patch.object(__main__, 'f') as mock_f:
g()
mock_f.assert_called_once_with(Foo())
AssertionError: Expected call: f(<__main__.Foo object at 0x7fd38411d0b8>)
Actual call: f(<__main__.Foo object at 0x7fd384111f98>)
Что я могу указать в качестве ожидаемого параметра, чтобы любой экземпляр Foo передал утверждение?
Комментарии:
1. Почему
assert_called_once()
тогда неassertIsInstance
полученное значение?2. Я думаю, это то, что я сделаю. Рад, что вы добавили это в свой ответ, оба решения являются информативными.
3. Мне очень нравится
mock_f.assert_called_once_with(AnyInstanceOf(Foo))
, но YMMV!4. Я попробую!
Ответ №1:
Одно простое решение — сделать это в два этапа:
with mock.patch.object(__main__, 'f') as mock_f:
g()
mock_f.assert_called_once()
self.assertIsInstance(mock_f.mock_calls[0].args[0], Foo)
Однако, если вы посмотрите на реализацию ANY
:
class _ANY(object):
"A helper object that compares equal to everything."
def __eq__(self, other):
return True
def __ne__(self, other):
return False
def __repr__(self):
return '<ANY>'
ANY = _ANY()
вы можете видеть, что это просто объект, который равен чему угодно. Таким образом, вы могли бы определить свой собственный эквивалент, равный любому экземпляру Foo
:
class AnyFoo:
"A helper object that compares equal to every instance of Foo."
def __eq__(self, other):
return isinstance(other, Foo)
def __ne__(self, other):
return not isinstance(other, Foo)
def __repr__(self):
return '<ANY Foo>'
ANY_FOO = AnyFoo()
Или в более общем смысле:
class AnyInstanceOf:
"A helper object that compares equal to every instance of the specified class."
def __init__(self, cls):
self.cls = cls
def __eq__(self, other):
return isinstance(other, self.cls)
def __ne__(self, other):
return not isinstance(other, self.cls)
def __repr__(self):
return f"<ANY {self.cls.__name__}>"
ANY_FOO = AnyInstanceOf(Foo)
В любом случае, вы можете использовать его по своему усмотрению ANY
:
with mock.patch.object(__main__, 'f') as mock_f:
g()
mock_f.assert_called_once_with(ANY_FOO)