2009-08-25 20 views
2

Wie kann ich Benutzereingaben in der Mitte einer Funktion simulieren, die durch einen Komponententest aufgerufen wird (mit dem Python 3-Komponententest)? Zum Beispiel habe ich eine Funktion foo() wer ist die Ausgabe, die ich testen. In der foo() Funktion, fragt es für die Benutzereingabe:Python 3 unittest simulieren Benutzereingabe

x = input(msg)

Und wird der Ausgang auf der Grundlage der eingegebenen:

print("input: {0}".format(x))

Ich möchte meine Unit-Test zu laufen foo(), geben Sie eine Eingabe und vergleichen Sie das Ergebnis mit das erwartete Ergebnis.

Antwort

7

Ich habe dieses Problem regelmäßig, wenn ich versuche, Code zu testen, der Dialoge für Benutzereingaben aufruft, und die gleiche Lösung sollte für beide funktionieren. Sie müssen eine neue Funktion, die an den Namen input in Ihrem Testbereich gebunden ist, mit derselben Signatur wie die Standardfunktion input angeben, die nur einen Testwert zurückgibt, ohne den Benutzer tatsächlich dazu aufzufordern. Je nachdem, wie Tests und Code sind Setup diese Injektion kann auf verschiedene Weise geschehen, so werde ich, dass für den Leser als Übung verlassen, aber Ihre Ersatzmethode wird etwas Einfaches wie sein:

def my_test_input(message): 
    return 7 

Natürlich könnten Sie auch den Inhalt von message einschalten, wenn das relevant wäre, und natürlich den Datentyp Ihrer Wahl zurückgeben. Sie können auch etwas flexibler und allgemein tun, die für die Wiederverwendung der gleichen Austauschverfahren in einer Reihe von Situationen erlaubt:

def my_test_input(retval, message): 
    return retval 

und dann würden Sie eine Teilfunktion in input injizieren:

import functools 
test_input_a = functools.partial(my_test_input, retval=7) 
test_input_b = functools.partial(my_test_input, retval="Foo") 

Weggehen test_input_a und test_input_b als Funktionen, die eine einzige message Argument, mit dem retval Argument bereits gebunden.

+0

Ich habe etwas ähnliches getan. Ich habe eine test_input-Funktion "test_input (msg)" erstellt, die das Standardverhalten von Input auf dem getesteten Modul überschreiben würde: "module.input = test_input". Ich setze den simulierten Eingangswert mit einer globalen Variable "sample_input", die vor der test_input-Funktion definiert ist, und setze sie vor jedem Testfall. – royvandewater

2

Da es aufgrund von Abhängigkeiten Schwierigkeiten beim Testen einiger Komponenten gibt, ist dies normalerweise ein Zeichen für schlechtes Design. Ihre foo Funktion sollte nicht von der globalen input Funktion abhängen, sondern von einem Parameter. Wenn Sie das Programm dann in einer Produktionsumgebung ausführen, verbinden Sie die Dinge so, dass foo aufgerufen wird mit dem Ergebnis, was input zurückgibt. So sollte foo lesen:

def foo(input): 
    # do something with input 

Diese Prüfung machen wird viel einfacher. Und wenn Ihre Tests IO Abhängigkeiten haben, sind sie nicht mehr Unit-Tests, sondern Funktionstests. Weitere Informationen zum Testen finden Sie unter Misko Hevery's blog.

+1

Vielleicht, aber * irgendwo *, sammelt jemand diese Eingabe.Wenn Sie die Methode testen möchten, müssen Sie entweder auf Funktionsprüfungstools zurückgreifen, die eine Benutzeroberfläche zum Testen auf dieser Ebene manipulieren, oder eine Injektion durchführen. Natürlich sollten Sie auch Funktionstests durchführen, die die Benutzeroberfläche manipulieren, aber dies sollte nur zum Testen der Benutzeroberfläche verwendet werden (z. B. dass Eingabe() die von Ihnen bereitgestellte Eingabe übernimmt) und keine Fehler in den Bereich der Nicht-UI-Implementierungsdetails bluten . –

+0

Nick, wenn das getestete System eine Legacy-Anwendung ist, in der das Refactoring sehr schwierig ist oder es einige Zeit braucht, aber du willst wirklich Charakterisierungs-Tests haben (die tatsächlich Refactoring unterstützen), dann ja, ich ' d verwende deine Methode. Wenn sich die Anwendung jedoch in der Entwicklung befindet, sollte sie neu strukturiert werden, damit Komponententests leicht geschrieben werden können. –

+0

@Nick Bastin: "Vielleicht, aber irgendwo sammelt jemand diese Eingabe. Wenn du die Methode testen willst, tu das ..." Das 'foo (input)' macht das. Es gibt kein "irgendwo" sonst, dass dies getestet werden muss. –