assert_has_calls
ist ein weiterer Ansatz für dieses Problem.
Aus den Dokumenten:
assert_has_calls (Aufrufe, any_order = False)
Bestätigen Sie, dass der Mock mit den angegebenen Aufrufen aufgerufen wurde. Die Liste mock_calls wird auf Aufrufe überprüft.
Wenn any_order False ist (Standardeinstellung), müssen die Aufrufe sequentiell sein. Vor oder nach den angegebenen Anrufen können zusätzliche Anrufe erfolgen.
Wenn any_order True ist, können die Aufrufe in beliebiger Reihenfolge erfolgen, sie müssen jedoch alle in mock_calls angezeigt werden.
Beispiel:
>>> from unittest.mock import call, Mock
>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
Quelle: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls
tuple
:isinstance(mock.call(1), tuple)
gibtTrue
. Sie fügten auch einige Methoden und Attribute hinzu.side_effect
Normalerweise ist mir die Reihenfolge der Anrufe egal, nur dass sie passiert sind. In diesem Fall verbinde ich mich
assert_any_call
mit einer Behauptung übercall_count
.Ich finde es einfacher zu lesen und zu verstehen als eine große Liste von Aufrufen, die an eine einzelne Methode übergeben werden.
Wenn Sie sich für die Bestellung interessieren oder mehrere identische Anrufe erwarten, ist dies
assert_has_calls
möglicherweise besser geeignet.Bearbeiten
Seit ich diese Antwort gepostet habe, habe ich meinen Testansatz im Allgemeinen überdacht. Ich denke, es ist erwähnenswert, dass Sie möglicherweise unangemessen testen oder ein Designproblem haben, wenn Ihr Test so kompliziert wird. Mocks dienen zum Testen der Kommunikation zwischen Objekten in einem objektorientierten Design. Wenn Ihr Design nicht objektorientiert ist (wie bei mehr prozeduralen oder funktionalen), ist das Modell möglicherweise völlig unangemessen. Möglicherweise ist in der Methode auch zu viel los, oder Sie testen interne Details, die am besten nicht verspottet werden. Ich habe die in dieser Methode erwähnte Strategie entwickelt, als mein Code nicht sehr objektorientiert war, und ich glaube, ich habe auch interne Details getestet, die am besten nicht verspottet worden wären.
quelle
do() if TEST_ENV=='prod' else dont()
), leicht erreichen, indem Sie sich über die von Ihnen vorgeschlagene Art und Weise lustig machen. Ein Nebeneffekt davon ist die Aufrechterhaltung von Tests pro Version (sagen wir, Codeänderungen zwischen Google Search API v1 und v2, Ihr Code wird Version 1 testen, egal wasMit dem
Mock.call_args_list
Attribut können Sie Parameter mit früheren Methodenaufrufen vergleichen. Das in Verbindung mitMock.call_count
Attribut sollte Ihnen die volle Kontrolle geben.quelle
assert_has_calls
Überprüft nur, ob die erwarteten Anrufe getätigt wurden, nicht jedoch, ob dies die einzigen sind.Ich muss das immer wieder nachschlagen, also hier ist meine Antwort.
Das Aktivieren mehrerer Methodenaufrufe für verschiedene Objekte derselben Klasse
Angenommen, wir haben eine Hochleistungsklasse (die wir verspotten wollen):
Hier ist ein Code, der zwei Instanzen der
HeavyDuty
Klasse verwendet:Hier ist ein Testfall für die
heavy_work
Funktion:Wir verspotten die
HeavyDuty
Klasse mitMockHeavyDuty
. Um Methodenaufrufe zu bestätigen, die von jederHeavyDuty
Instanz kommen, müssen wirMockHeavyDuty.return_value.assert_has_calls
stattdessen auf verweisenMockHeavyDuty.assert_has_calls
. Außerdem müssenexpected_calls
wir in der Liste von angeben, für welchen Methodennamen wir Aufrufe geltend machen möchten. Unsere Liste besteht also nicht nur aus Anrufencall.do_work
, sondern aus Anrufencall
.Das Ausüben des Testfalls zeigt uns, dass es erfolgreich ist:
Wenn wir die
heavy_work
Funktion ändern , schlägt der Test fehl und es wird eine hilfreiche Fehlermeldung ausgegeben:Aktivieren mehrerer Aufrufe einer Funktion
Im Gegensatz dazu sehen Sie hier ein Beispiel, das zeigt, wie mehrere Aufrufe einer Funktion verspottet werden:
Es gibt zwei Hauptunterschiede. Die erste ist, dass wir beim Verspotten einer Funktion unsere erwarteten Aufrufe mit
call
anstatt mit verwendencall.some_method
. Das zweite ist , dass wir rufen Sieassert_has_calls
aufmock_work_function
, anstatt aufmock_work_function.return_value
.quelle