Ich muss JUnit-Tests für eine alte Anwendung schreiben, die schlecht gestaltet ist und viele Fehlermeldungen in die Standardausgabe schreibt. Wenn sich die getResponse(String request)
Methode korrekt verhält, wird eine XML-Antwort zurückgegeben:
@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
Wenn es jedoch fehlerhaftes XML erhält oder die Anforderung nicht versteht, gibt es null
einige Daten zurück und schreibt sie in die Standardausgabe.
Gibt es eine Möglichkeit, die Konsolenausgabe in JUnit zu aktivieren? Um Fälle zu fangen wie:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Antworten:
Die Verwendung von ByteArrayOutputStream und System.setXXX ist einfach:
Beispiel Testfälle:
Ich habe diesen Code verwendet, um die Befehlszeilenoption zu testen (wobei behauptet wurde, dass -version die Versionszeichenfolge usw. usw. ausgibt).
Bearbeiten: Frühere Versionen dieser Antwort wurden
System.setOut(null)
nach den Tests aufgerufen . Dies ist die Ursache für NullPointerExceptions, auf die sich Kommentatoren beziehen.quelle
NullPointerException
in anderen Tests auf einen gestoßen , nachdem ich einen Nullfehlerstrom wie oben vorgeschlagen festgelegt hatte (injava.io.writer(Object)
, intern von einem XML-Validator aufgerufen). Ich würde vorschlagen, stattdessen das Original in einem Feld zu speichernoldStdErr = System.err
und dies in der@After
Methode wiederherzustellen .Ich weiß, dass dies ein alter Thread ist, aber es gibt eine nette Bibliothek, um dies zu tun:
Systemregeln
Beispiel aus den Dokumenten:
Sie können damit auch Trap
System.exit(-1)
und andere Dinge abfangen, auf die ein Befehlszeilentool getestet werden müsste.quelle
Anstatt umzuleiten
System.out
, würde ich die verwendete Klasse umgestalten,System.out.println()
indem ich aPrintStream
als Kollaborateur übergebe und dannSystem.out
in der Produktion und einen Testspion im Test verwende. Verwenden Sie also Dependency Injection, um die direkte Verwendung des Standardausgabestreams zu vermeiden.In Produktion
Im Test
Diskussion
Auf diese Weise kann die zu testende Klasse durch einfaches Refactoring getestet werden, ohne dass eine indirekte Umleitung der Standardausgabe oder ein unklares Abfangen mit einer Systemregel erforderlich ist.
quelle
ConsoleWriter
ist das Testobjekt,Sie können den System.out- Druckstrom über setOut () (und für
in
underr
) festlegen . Können Sie dies in einen Druckdatenstrom umleiten, der in eine Zeichenfolge aufzeichnet, und diesen dann überprüfen? Das scheint der einfachste Mechanismus zu sein.(Ich würde empfehlen, die App irgendwann in ein Protokollierungsframework zu konvertieren - aber ich vermute, dass Sie sich dessen bereits bewusst sind!)
quelle
Etwas abseits des Themas, aber falls einige Leute (wie ich, als ich diesen Thread zum ersten Mal fand) daran interessiert sein könnten, die Protokollausgabe über SLF4J zu erfassen, könnte JUnit von Commons-Testing
@Rule
helfen:Haftungsausschluss :
log4j
,log4j2
undlogback
sind zur Zeit verfügbar, aber ich bin glücklich , mehr hinzuzufügen.quelle
Die Antwort von @dfa ist großartig, also bin ich noch einen Schritt weiter gegangen, um das Testen von Ausgabeblöcken zu ermöglichen.
Zuerst habe ich
TestHelper
mit einer Methode erstelltcaptureOutput
, die die nervige Klasse akzeptiertCaptureTest
. Die CaptureOutput-Methode übernimmt das Festlegen und Herunterfahren der Ausgabestreams. Wenn die Umsetzung vonCaptureOutput
‚s -test
Methode aufgerufen wird, hat sie Zugriff auf den Ausgang für den Testblock erzeugen.Quelle für TestHelper:
Beachten Sie, dass TestHelper und CaptureTest in derselben Datei definiert sind.
Anschließend können Sie in Ihrem Test den statischen CaptureOutput importieren. Hier ist ein Beispiel mit JUnit:
quelle
Wenn Sie Spring Boot verwenden (Sie haben erwähnt, dass Sie mit einer alten Anwendung arbeiten, also wahrscheinlich nicht, aber für andere von Nutzen sein könnten), können Sie org.springframework.boot.test.rule.OutputCapture verwenden auf folgende Art:
quelle
Basierend auf der Antwort von @ dfa und einer weiteren Antwort, die zeigt, wie System.in getestet wird , möchte ich meine Lösung freigeben , um einem Programm eine Eingabe zu geben und seine Ausgabe zu testen.
Als Referenz verwende ich JUnit 4.12.
Angenommen, wir haben dieses Programm, das einfach Eingabe zu Ausgabe repliziert:
Um es zu testen, können wir die folgende Klasse verwenden:
Ich werde nicht viel erklären, weil ich glaube, dass der Code lesbar ist und ich meine Quellen zitiert habe.
Wenn JUnit ausgeführt
testCase1()
wird, werden die Hilfsmethoden in der Reihenfolge aufgerufen, in der sie angezeigt werden:setUpOutput()
wegen der@Before
AnmerkungprovideInput(String data)
, angerufen vontestCase1()
getOutput()
, angerufen vontestCase1()
restoreSystemInputOutput()
wegen der@After
AnmerkungIch habe nicht getestet,
System.err
weil ich es nicht brauchte, aber es sollte einfach zu implementieren sein, ähnlich wie beim TestenSystem.out
.quelle
Sie möchten den Stream system.out nicht umleiten, da dieser für die GESAMTE JVM umleitet. Alles andere, was auf der JVM läuft, kann durcheinander geraten. Es gibt bessere Möglichkeiten, die Eingabe / Ausgabe zu testen. Schauen Sie in Stubs / Mocks.
quelle
Vollständiges JUnit 5-Beispiel zum Testen
System.out
(ersetzen Sie das when-Teil):quelle
Sie können nicht direkt mit system.out.println oder mit logger api drucken, während Sie JUnit verwenden . Wenn Sie jedoch Werte überprüfen möchten, können Sie diese einfach verwenden
Es wird unter Assertionsfehler geworfen:
Ihr Wert sollte 21,92 sein. Wenn Sie nun mit diesem Wert wie unten testen, besteht Ihr Testfall.
quelle
für raus
für err
quelle
@Rule
, anstatt sie in Ihrem Test inline zu machen. Insbesondere wenn Ihre Behauptung fehlschlägt, wird der zweiteSystem.setOut/Err
Anruf nicht erreicht.