wake-up-neo.com

Python verspotten mehrere Rückgabewerte

Ich verwende Pythons mock.patch und möchte den Rückgabewert für jeden Aufruf ändern. Hier ist die Einschränkung: Die gepatchte Funktion hat keine Eingaben, daher kann ich den Rückgabewert basierend auf der Eingabe nicht ä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 verfälschen. 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 ungültig 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.)


Nicht ein Dup von diese Frage hauptsächlich, weil ich nicht die Möglichkeit habe, die Eingänge zu variieren.

Einer der Kommentare in der Antwort auf diese Frage ist in der gleichen Richtung, aber es wurde keine Antwort/Kommentar bereitgestellt.

120
Nick Humrich

Sie können side_effect Ein iterable zuweisen, und der Mock gibt bei jedem Aufruf den nächsten Wert in der Sequenz zurück:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Zitiere die Mock() Dokumentation :

Wenn side_effect ein Iterationswert ist, gibt jeder Aufruf des Mocks den nächsten Wert aus dem Iterationswert zurück.

Abgesehen davon funktioniert der Test response is not 'y' or 'n' or 'yes' or 'no' nicht ; Sie fragen, ob der Ausdruck (response is not 'y') wahr ist oder 'y' wahr ist (immer der Fall, eine nicht leere Zeichenfolge ist immer wahr) usw. Die verschiedenen Ausdrücke auf beiden Seiten von or -Operatoren sind unabhängig. Siehe Wie teste ich eine Variable gegen mehrere Werte?

Sie sollten also nicht is verwenden, um eine Zeichenfolge zu testen. Der CPython-Interpreter darf verwendet Zeichenfolgenobjekte wieder nter bestimmten Umständen , aber dies ist kein Verhalten, auf das Sie zählen sollten.

Verwenden Sie als solche:

response not in ('y', 'n', 'yes', 'no')

stattdessen; Dabei wird mit equality tests (==) ermittelt, ob response auf eine Zeichenfolge mit demselben Inhalt (Wert) verweist.

Gleiches gilt für response == 'y' or 'yes'; Verwenden Sie stattdessen response in ('y', 'yes').

231
Martijn Pieters