2017-02-11 3 views
1

Was ich tun möchte, ist neu erstellte Instanz von BufferedReader zu verspotten. Hier ist der Code, der getestet werden soll:PowerkMocking BufferedReader läuft intermittierend

A.java

... 
@Override 
public String read(String fileName) throws IOException { 
    ... 

    try { 
     fileReader = new FileReader(fileName); 
     bufferedReader = new BufferedReader(fileReader); 
     String tmp; 
     StringBuilder builder = new StringBuilder(); 
     while ((tmp = bufferedReader.readLine()) != null) { 
      builder.append(tmp); 
     } 
     return builder.toString(); 
    } catch (IOException e) { 
     ... 
    } finally { 
     ... 
    } 
} 
... 

Was ich zu tun haben, ist sowohl FileReader Schöpfung und BufferedReader Schöpfung PowerMock.

ATest.java

@RunWith(PowerMockRunner.class) 
@PrepareForTest(A.class) 
public class ATest { 

    @Mock 
    private FileReader fileReader; 
    @Mock 
    private BufferedReader bufferedReader; 
    ... 

    @Test 
    public void test() throws Exception { 
     PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader); 
     PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader); 
     PowerMockito.doAnswer(new Answer() { 
      public Object answer(InvocationOnMock invocation) throws Throwable { 
       return "test"; 
      } 
     }).when(bufferedReader).readLine(); 
     assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"}); 
    } 
} 

Aber dann der Test endet nie. Ich kann es nicht einmal debuggen.

Sobald PowerMockito.doAnswer() entfernt wird, wird der Code ausgeführt (und ist zum Debuggen verfügbar). Ich habe auch versucht, Mockito.mock() statt PowerMockito.doAnswer() zu verwenden, es hilft nicht.

Was kann zu einer zwischenzeitlichen Ausführung des Tests führen?

Antwort

1

Das Problem war, dass ich auch Wert nach dem ersten bufferedReader.readLine() mockte, denn sonst würde es immer den verspotteten Wert zurückgeben, also nicht enden.

Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null); 

HINWEIS

Obwohl dies die eigentliche Antwort auf die Frage ist, aber man sollte das Design der Wahl GhostCat has suggested in einer anderen Antwort in Erwägung ziehen (was ich auch tat schließlich).

3

Nur eine andere Perspektive: Man könnte sagen, dass Ihr echtes Problem in Ihrem Code sind die beiden Anrufe zu new() für Filereader/BufferedReader.

Was passiert, wenn Sie einen Reader an diese Methode übergeben haben? anstelle einer Zeichenfolge, die einen Dateinamen angibt?

Was passiert, wenn Sie eine "ReaderFactory" an die zugrunde liegende Klasse übergeben, die diese Methode read(String) enthält? (Wo man würde Dependency Injection verwenden diese Fabrik in Ihre Klasse zu erhalten)

Dann: Sie würden in einem suchen verbessert Design - und Sie würden nicht brauchen PowerMock zu verwenden. Sie könnten zurücktreten und mit Mockito oder EasyMock gehen; da es keine Notwendigkeit mehr geben würde, Aufrufe an new zu mokieren.

Also, meine Antwort ist: Sie erstellt schwer zu testen Code. Jetzt versuchen Sie, ein Designproblem mit dem großen (hässlichen) PowerMock Hammer zu beheben. Ja, das wird funktionieren. Aber es ist nur die zweitbeste Alternative.

Die sinnvollere Option ist es, zu lernen, wie man testbaren Code schreibt (starten Sie zum Beispiel here); und schreiben Sie testbaren Code. Und hören Sie auf, PowerMock zu verwenden (ich habe das viele Monate zurück gemacht; nach einer Menge von PowerMock-induzierten Schmerzen; und ich habe nie jemals bedauerte diese Entscheidung).

+0

Danke, macht Sinn. – azizbekian

+1

Sie sind herzlich willkommen. Ich bin immer froh, wenn die Leute nicht auf solche Antworten mit "Aber es ist nicht mein Code, den ich testen muss, so PowerMock ist die einzige Wahl für mich" ;-) – GhostCat

+1

Und nur als Randnotiz: Es gibt FileUtilities.readAllLines () - nimmt eine Zeichenkette und gibt eine Liste aller Zeilen in dieser Datei zurück (die Sie leicht eingeben könnten, um eine einzelne Zeichenkette zu erhalten). Vielleicht könnte man statt eines zehnten Mal "full read in string" auch nur eine der vorhandenen Implementierungen verwenden. Ich bin mir sicher, Apache Commons, Guave, sie alle haben Methoden dafür! – GhostCat