Soweit ich weiß, Mockgibt es keine Möglichkeit, über das zu erreichen, was Sie wollen assert_called_with. Sie könnten die zugreifen call_argsund call_args_listMitglieder und die Behauptungen manuell durchführen.
Dies ist jedoch eine einfache (und schmutzige) Methode, um fast das zu erreichen, was Sie wollen. Sie müssen eine Klasse implementieren, deren __eq__Methode immer Folgendes zurückgibt True:
def Any(cls):
class Any(cls):
def __eq__(self, other):
return True
return Any()
Verwenden Sie es als:
In [14]: caller = mock.Mock(return_value=None)
In [15]: caller(1,2,3, arg=True)
In [16]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=True)
In [17]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-17-c604faa06bd0> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)
/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
724 if self.call_args != (args, kwargs):
725 msg = self._format_mock_failure_message(args, kwargs)
--> 726 raise AssertionError(msg)
727
728
AssertionError: Expected call: mock(0, 0, 0, arg=False)
Actual call: mock(1, 2, 3, arg=True)
Wie Sie sehen können, wird nur nach dem gesucht arg. Sie müssen Unterklassen von erstellen int, sonst funktionieren die Vergleiche nicht 1 . Sie müssen jedoch noch alle Argumente angeben. Wenn Sie viele Argumente haben, können Sie Ihren Code mithilfe des Tupel-Entpackens verkürzen:
In [18]: caller(1,2,3, arg=True)
In [19]: caller.assert_called_with(*[Any(int)]*3, arg=True)
Abgesehen davon kann ich mir keine Möglichkeit vorstellen, zu vermeiden, dass alle Parameter an Sie übergeben assert_called_withund so bearbeitet werden, wie Sie es beabsichtigen.
Die obige Lösung kann erweitert werden, um nach anderen Argumenttypen zu suchen. Zum Beispiel:
In [21]: def Any(cls):
...: class Any(cls):
...: def __eq__(self, other):
...: return isinstance(other, cls)
...: return Any()
In [22]: caller(1, 2.0, "string", {1:1}, [1,2,3])
In [23]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(list))
In [24]: caller(1, 2.0, "string", {1:1}, [1,2,3])
In [25]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-25-f607a20dd665> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))
/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
724 if self.call_args != (args, kwargs):
725 msg = self._format_mock_failure_message(args, kwargs)
--> 726 raise AssertionError(msg)
727
728
AssertionError: Expected call: mock(0, 0.0, '', {}, ())
Actual call: mock(1, 2.0, 'string', {1: 1}, [1, 2, 3])
Dies erlaubt jedoch keine Argumente, die beispielsweise sowohl ein intals auch ein sein können str. Das Zulassen mehrerer Argumente für Anyund die Verwendung von Mehrfachvererbung hilft nicht. Wir können dies mit lösenabc.ABCMeta
def Any(*cls):
class Any(metaclass=abc.ABCMeta):
def __eq__(self, other):
return isinstance(other, cls)
for c in cls:
Any.register(c)
return Any()
Beispiel:
In [41]: caller(1, "ciao")
In [42]: caller.assert_called_with(Any(int, str), Any(int, str))
In [43]: caller("Hello, World!", 2)
In [44]: caller.assert_called_with(Any(int, str), Any(int, str))
1 Ich habe den Namen Anyfür die Funktion verwendet, da sie im Code "als Klasse verwendet" wird. Auch anyist ein eingebauter ...
requests-mockkönnte das Modul auch interessant sein.