C# unit-test für eine Methode, die fordert, Konsole.ReadLine()
Möchte ich zum erstellen einer unit test für eine member-Funktion einer Klasse aufgerufen ScoreBoard
die Speicherung der top fünf Spieler in einem Spiel.
Das problem ist, dass die Methode, die ich erstellt einen test für (SignInScoreBoard
) ruft Console.ReadLine()
so kann der Benutzer geben Sie Ihren Namen ein:
public void SignInScoreBoard(int steps)
{
if (topScored.Count < 5)
{
Console.Write(ASK_FOR_NAME_MESSAGE);
string name = Console.ReadLine();
KeyValuePair<string, int> pair = new KeyValuePair<string, int>(name, steps);
topScored.Insert(topScored.Count, pair);
}
else
{
if (steps < topScored[4].Value)
{
topScored.RemoveAt(4);
Console.Write(ASK_FOR_NAME_MESSAGE);
string name = Console.ReadLine();
topScored.Insert(4, new KeyValuePair<string, int>(name, steps));
}
}
}
Gibt es eine Möglichkeit einfügen, wie zehn Benutzer, so kann ich überprüfen, ob die fünf mit weniger moves (Schritte) gespeichert sind?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Müssen Sie umgestalten, die Zeilen von code, der call-Konsole.ReadLine in einem separaten Objekt, so können Sie stub mit Ihrer eigenen Umsetzung in Ihren tests.
Als kurzes Beispiel könnte man einfach eine Klasse in etwa so:
Dann, in Ihrer Methode, umgestalten, es zu nehmen, wird eine Instanz dieser Klasse statt. Jedoch, die beim test der Zeit, könnte man überschreiben Sie diese mit einer test-Implementierung:
Beim testen, wechseln Sie die Umsetzung mit einer test-Umsetzung.
Gewährt, würde ich persönlich benutze ein framework, um dies zu erleichtern, und verwenden Sie eine saubere Schnittstelle anstelle dieser Implementierungen, aber hoffentlich die oben ist genug, um Ihnen die richtige Idee...
ConsoleNameRetriever
zwingen würde, einen modal-dialog UI. Ich bin für MVVM, weil seine Benutzeroberfläche semi-Abstraktion, aber in diesem Fall, die einzige anständige Implementierungen wäreConsole
oder test-stub... Das ist, warum sehe ich dies als refactoring nur für die Zwecke der Prüfung; der code muss wirklich komplett überarbeitet.Sollten Sie umgestalten von code zum entfernen der Abhängigkeit von der Konsole aus diesem code.
Beispielsweise, Sie könnten dies tun:
dann ändern Sie Ihren code wie folgt:
Laufen Sie in die Produktion übergeben Sie eine Instanz dieser Klasse:
Jedoch bei test-Zeit, verwenden Sie diese:
Dies macht den code einfacher zu testen.
Natürlich, wenn Sie wollen, um zu überprüfen, dass die korrekte Ausgabe ist geschrieben, wie gut, müssen Sie code hinzufügen, um die write-Methoden zu sammeln, den Ausgang, so dass Sie geltend machen kann, auf die es in den test-code.
Können Sie Maulwürfe zu ersetzen
Console.ReadLine
mit Ihrer eigenen Methode, ohne änderungen am code auf allen (entwerfen und implementieren einer abstrakten Konsole, mit Unterstützung für dependency injection ist alles völlig unnötig).Warum nicht erstellen Sie einen neuen stream (file/memory) für beide stdin und stdout, dann umleiten von Eingabe - /Ausgabe auf Ihren neuen streams vor dem Aufruf der Methode? Sie könnten dann prüfen Sie den Inhalt der streams, nachdem die Methode beendet wurde.
Eher als Abstraktion der Konsole, würde ich lieber eine Komponente erstellen, die Kapselung dieser Logik, und testen Sie diese Komponente, und verwenden Sie es in der Konsole.
In den test-Fall, Sie können es nennen, wie
In Ihre normale Durchführung, nennen Sie es, wie
Wenn Sie mit C# 4.0, können Sie die Konsole.ReadLine einen Standardwert, indem Sie sagen,
Ich kann nicht glauben, wie viele Menschen geantwortet haben, ohne die Frage richtig. Das problem ist die Methode in Frage, nicht mehr als eine Sache, also fragt nach einem Namen und fügt den top-score. Jede Bezugnahme auf Konsole herausgenommen werden kann dieser Methode und der name übergeben werden sollen, in statt:
Für andere tests werden Sie wahrscheinlich wollen, um abstrakte, aus der Lektüre der Ausgabe in der Konsole wie bereits in den anderen Antworten.
Ich hatte ein ähnliches Problem vor paar Tagen. Kapselung Console-Klasse schien mir wie overkill für mich. Basierend auf der KISS-Prinzip und IoC/DI Prinzip habe ich geputtet Abhängigkeiten für Schriftsteller (output) und Leser (- Eingang) an den Konstruktor. Lassen Sie mich das Beispiel.
Können wir davon ausgehen, einfache Bestätigung Anbieter definiert durch die Schnittstelle
IConfirmationProvider
und seine Umsetzung ist
Jetzt können Sie leicht testen Sie Ihre Implementierung, wenn Sie Spritzen Abhängigkeit zu Ihrem
TextWriter
undTextReader
(in diesem BeispielStreamReader
alsTextReader
)Und verwenden Sie Ihre Implementierung aus apllication standard-Weg mit Standardeinstellungen (
Console.In
alsTextReader
undConsole.Out
alsTextWriter
)Ist das all - eine zusätzliche ctor mit Feldern Initialisierung.