Ich verwende pythons mock.patch und möchte den Rückgabewert für jeden Aufruf ändern. Hier ist die Einschränkung: Die zu patchende Funktion hat keine Eingaben, daher kann ich den Rückgabewert nicht basierend auf der Eingabe ändern.
Hier ist mein Code als Referenz.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
Mein Testcode:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
ist nur eine plattformunabhängige (Python 2 und 3) Version von "input". Letztendlich versuche ich also, die Benutzereingaben zu verspotten. Ich habe versucht, eine Liste für den Rückgabewert zu verwenden, aber das funktioniert nicht.
Sie können sehen, dass ich hier nur eine Endlosschleife bekomme, wenn der Rückgabewert etwas Ungültiges ist. Ich brauche also eine Möglichkeit, den Rückgabewert zu ändern, damit mein Test tatsächlich beendet wird.
(Eine andere Möglichkeit, diese Frage zu beantworten, könnte darin bestehen, zu erklären, wie ich Benutzereingaben in einem Komponententest nachahmen kann.)
Kein Problem mit dieser Frage, vor allem, weil ich nicht in der Lage bin, die Eingaben zu variieren.
Einer der Kommentare der Antwort auf diese Frage ist in die gleiche Richtung, es wurde jedoch keine Antwort / kein Kommentar abgegeben.
quelle
response is not 'y' or 'n' or 'yes' or 'no'
in nicht zu tun , was Sie denken , es tut. Siehe Wie teste ich eine Variable gegen mehrere Werte? und Sie sollten nicht verwendenis
, um Zeichenfolgenwerte zu vergleichen, verwenden==
, um Werte zu vergleichen , nicht Objektidentitäten.is
String-Literale zu vergleichen. Tu das nicht. Die Tatsache, dass es (manchmal) funktioniert, ist nur ein Implementierungsdetail in CPython. Auchresponse is not 'y' or 'n' or 'yes' or 'no'
tut wahrscheinlich nicht, was Sie denken, dass es ist ...Antworten:
Sie können einen zuweisen iterable zu
side_effect
, und das Mock wird den nächsten Wert in der Folge bei jedem Aufruf zurückkehren wird:Zitieren der
Mock()
Dokumentation :Als Nebenwirkung der Test
response is not 'y' or 'n' or 'yes' or 'no'
wird nicht funktionieren; Sie fragen, ob der Ausdruck(response is not 'y')
wahr oder'y'
wahr ist (immer der Fall, eine nicht leere Zeichenfolge ist immer wahr) usw. Die verschiedenen Ausdrücke auf beiden Seiten deror
Operatoren sind unabhängig . Siehe Wie teste ich eine Variable gegen mehrere Werte?Sie sollten auch nicht
is
zum Testen gegen eine Zeichenfolge verwenden. Der CPython-Interpreter kann unter bestimmten Umständen Zeichenfolgenobjekte wiederverwenden. Dies ist jedoch kein Verhalten, auf das Sie zählen sollten.Verwenden Sie daher:
stattdessen; Dabei werden Gleichheitstests (
==
) verwendet, um festzustellen, obresponse
auf eine Zeichenfolge mit demselben Inhalt (Wert) verwiesen wird.Gleiches gilt für
response == 'y' or 'yes'
; Verwenden Sieresponse in ('y', 'yes')
stattdessen.quelle
mock
? Gibt es eine Möglichkeit, Patches mit MagicMock zu verwenden, wie ich es mit Standard-Mock mache?Mock
Klasse.m.side_effect = iter(['foo', 'bar', 'baz'])
).lambda
(eine Funktion) erzeugt, keineMagicMock
. Ein Funktionsobjekt nicht hat Eigenschaften, so dass dasside_effect
Attribut hat eine iterable sein. Sie sollten die Methode jedoch nicht so spezifizieren. Bessere Verwendungmock.patch.object(requests.Session, 'post')
; Dies führt zu einem Patcher-Objekt, das die Methode automatisch automatisch spezifiziert undside_effect
ordnungsgemäß unterstützt .StopIteration
wird ausgelöst . Sie können jeden Iterator verwenden, also können Sie einmalitertools.chain(['Foo'], itertools.repeat('Bar'))
produzierenFoo
und dann für immer produzierenBar
.