Java InputStream verspotten


74

Bitte geben Sie Zeiger an, damit ich das Java InputStream-Objekt verspotten kann. Dies ist die Codezeile, die ich verspotten möchte:

InputStreamReader inputData = new InputStreamReader(System.in);
bufferdReader = new BufferedReader(inputData);
bufferdReader.readLine(); 

1
Ist Ihr Problem das System.in? Sie möchten Ihren Code wahrscheinlich so umgestalten, dass anstelle von System.in ein anderer InputStream übergeben wird. Dann können Sie ein beliebiges Mocking-Framework (wie in den Antworten erwähnt) verwenden, um diesen InputStream zu verspotten.
Phtrivier

Antworten:


58
BufferedReader bufferedReader = org.mockito.Mockito.mock(BufferedReader.class);
when(bufferedReader.readLine())
  .thenReturn("first line")
  .thenReturn("second line");

org.junit.Assert.when(new Client(bufferedReader).parseLine())
  .thenEquals(IsEqual.equalTo("first line"));

Vielen Dank für die schnelle Antwort .. werde es überprüfen
Reji

Wie importiere ich Client? Es tut mir leid, aber ich bin neu in Mockito und Junit. Sie verwenden Client in dieser Zeile:org.junit.Assert.when(new Client(bufferedReader).parseLine())
Alejandro Sanchez

Client ist eine Klasse, die den gepufferten Leser verwendet, um Zeile für Zeile zu lesen und zu analysieren
Boris Pavlović

109

Sie können commons-io verwenden , um einige Stub-Eingabestreams zu erstellen:

InputStream stubInputStream = 
     IOUtils.toInputStream("some test data for my input stream", "UTF-8");

1
Wenn Sie den Stream mehrmals verwenden möchten, wie würden Sie ihn nach der Verwendung zurücksetzen?
Exic

Sie können es in einen BufferedInputStream einbinden und mark () und reset () verwenden. Aber wahrscheinlich ist es einfacher, eine neue in Ihrer Setup-Methode zu instanziieren (vorausgesetzt, wir sprechen hier noch über das Testen).
Eric

1
seit v2.3 müssen Sie den Zeichensatz hinzufügen, zum Beispiel : toInputStream("someString", "UTF-8"). Die Version mit nur String als Parameter ist veraltet.
JonyD

Danke @JonyD! Ich habe die Antwort aktualisiert, um den Zeichensatzparameter einzuschließen.
Eric

Meine Lieblingsantwort! Ich würde nur hinzufügen, dass Sie anstelle der nicht typsicheren ZeichenfolgeStandardCharsets.UTF_8
dcasadevall

96

Sie können einfach a verwenden ByteArrayInputStreamund es mit Ihren Testdaten füllen.

@ Brads Beispiel aus den Kommentaren:

InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());

Zusätzlicher Vorteil ist, dass ByteArrayInputStreamunterstützt mark()undreset()
Hank

4
Schön und einfach ...InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());
Brad

20

Ich bin mit der ausgewählten Antwort auf diese Frage nicht einverstanden. Mocking-Frameworks wie Mockito sind nett und alle, aber wenn Standard-Java-API verfügbar ist, können Sie dies stattdessen in Betracht ziehen.

dh

BufferedReader reader = new BufferedReader(new StringReader("some string"));

Warum sollten Sie in Ihren Testklassen ein Mock-Objekt verwenden, wenn Sie ein reales Objekt mit all seinem Status und Verhalten verwenden könnten?

Um mehr darüber zu erfahren, wie dies funktioniert, können Sie das Designmuster "Dekorateur" nachschlagen.


3
Hier ist ein Anwendungsfall: Verspotten Sie mehrere verschiedene Aufrufe, z. B. in einer Schleife (falsche Eingabe1 -> falsche Eingabe2 -> richtige Eingabe3).
Jan Groth

Behalten Sie Ihren InputStream-Code und Ihren Reader-Code in separaten Klassen, genau wie die Java-API. Lassen Sie Ihre Testklasse eine Implementierung von Reader und nicht InputStream bestehen und übergeben Sie im Produktionscode auch eine Implementierung von Reader an die Klasse, die Ihre Daten liest / Ihre Datenverarbeitung durchführt.
John Deverall

3

Ändern Sie Ihr Objekt so, dass es einfacher zu testen ist.

public MyObject {
    private InputStream inputStream;

    public void setInputStream(InputStream inputStream) {this.inputStream = inputStream;}

    public void whatever() {
        InputStreamReader inputData = new InputStreamReader(inputStream);
        bufferdReader = new BufferedReader(inputData);
        bufferdReader.readLine(); 
    }
}

Wenn Sie dann Ihr Objekt verwenden, initialisieren Sie zuerst seinen inputStream:

MyObject myObject = new MyObject();
myObject.setInputStream(System.in);

Jetzt haben Sie ein Objekt, mit dem Sie es mit einer beliebigen Implementierung von InputStream testen können (ByteArrayInputStream ist ein guter Versuch).


2
@Test
    public void testReadFile() {
    TestClass ClassName = Mockito.mock(TestClass.class);
     InputStream in = Mockito.mock(InputStream.class);
     InputStreamReader inr =Mockito.mock(InputStreamReader.class);
     BufferedReader bufferedReader =Mockito.mock(BufferedReader.class);
       try {
         PowerMockito.whenNew(InputStreamReader.class).withArguments(in).thenReturn(inr);
         PowerMockito.whenNew(BufferedReader.class).withArguments(inr).thenReturn(bufferedReader);
         String line1 = "example line";
         PowerMockito.when(bufferedReader.readLine()).thenReturn(line1).thenReturn(null);
         method return type = Whitebox.invokeMethod(ClassName, "MethodName", arguement);
         assertEquals("result is::","expected", actual);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

2
String testString = "test\nstring";
InputStream stream = new ByteArrayInputStream(testString.getBytes(StandardCharsets.UTF_8));

BufferedReader reader = new BufferedReader(new InputStreamReader(stream));

Assert.assertEquals("test", reader.readLine());
Assert.assertEquals("string", reader.readLine());

1

Die beste Lösung, die ich gefunden habe, ist die Verwendung

final InputStream inputStream1 = IOUtils.toInputStream("yourdata");

und wickeln Sie dann den Inpustream in bufferedReader ein, um den Test am besten um den Eingabestream zu schreiben


1
Dies fügt eine weitere Abhängigkeit von IOUtils hinzu, wodurch Ihr Testcode größer wird. Nicht der gewünschte Effekt, den wir von kleinen Unit-Tests
erwarten

0

Angenommen, Sie verwenden Maven, können Sie eine Ressource in den Ordner "src / test / resources /" legen, beispielsweise "src / test / resources / wunderbar-mock-data.xml ". Dann können Sie in Ihnen Folgendes tun:

    String resourceInputFile = "/database-insert-test.xml";
    URL url = this.getClass().getResource(resourceInputFile);
    Assert.assertNotNull("Can't find resource " + resourceInputFile, url);

    InputStream inputStream = url.openStream();

    // Now you can just use the inputStream for method calls requiring this param
    (...)

In diesem Beispiel ist die URL varialble null, wenn die angegebene Ressource im aktuellen Klassenpfad nicht gefunden werden kann. Mit diesem Ansatz können Sie mehrere Szenarien in verschiedene resourceInputFile (s) einfügen ... Denken Sie auch daran, dass alle Arten von Ressourcen unter "src / test / resources /" (nicht nur XML-Dateien, wie z. B. txt, html, jpeg usw.) gespeichert sind. ) sind normalerweise als Klassenpfadressourcen aus allen jUnit-Tests verfügbar.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.