2013-07-16 5 views
6

Ich habe eine Klasse wie die folgende;Mock ein privates statisches Feld mit JMockit?

class ClassA { 
    private static File myDir; 

    // myDir is created at some stage 

    private static String findFile(final String fileName) { 
     for (final String actualBackupFileName : myDir.list()) { 
      if (actualBackupFileName.startsWith(removeExtensionFrom(backupFile))) { 
       return actualBackupFileName; 
      } 
     } 
    } 
} 

Also, im Grunde möchte ich diese Klasse testen, indem Sie die File-Klasse verspotten, so dass, wenn die Liste() auf sie aufgerufen wird es eine Liste von Strings zurück, die ich in meiner Test-Klasse definieren.

Ich habe die folgenden, aber es funktioniert nicht in der Minute, es ist wahrscheinlich etwas offensichtlich Ich mache falsch - ich bin neu bei JMockit - jede Hilfe wird sehr geschätzt!

@Mocked("list") File myDir; 

@Test 
    public void testClassA() { 
    final String[] files = {"file1-bla.txt"}; 

    new NonStrictExpectations() {{ 
     new File(anyString).list(); 
     returns(files); 
    }}; 

    String returnedFileName = Deencapsulation.invoke(ClassA.class, "findFile","file1.txt"); 

    // assert returnedFileName is equal to "file1-bla.txt" 
    } 

Bei der Ausführung des obigen Test ich eine Nullpointer für das myDir Feld in KlasseA bekommen - so sieht es aus wie es ist nicht richtig verspottet zu werden?

Antwort

10

JMockit (oder andere spöttische Werkzeug) nicht Mock Felder oder Variablen, es spottet Typen (Klassen, Schnittstellen usw.) Wenn die Instanzen dieser Typen in dem zu prüfenden Code gespeichert ist nicht relevant.

Beispiel Test für ClassA:

@Test 
public void testClassA(@Mocked File myDir) 
{ 
    new Expectations() {{ myDir.list(); result = "file1-bla.txt"; }}; 

    String returnedFileName = new ClassA().publicMethodThatCallsFindFile("file1.txt"); 

    assertEquals("file1-bla.txt", returnedFileName); 
} 

Die oben funktionieren sollte. Beachten Sie, dass das Testen von private Methoden direkt (oder Zugriff auf private Felder) als schlechte Praxis gilt, also habe ich es hier vermieden. Vermeiden Sie es auch, sich über die Klasse File lustig zu machen. Testen Sie stattdessen nur Ihre public-Methoden und verwenden Sie tatsächliche Dateien, anstatt das Dateisystem zu verspotten.

+0

Excellent, tausend Dank für deine Hilfe Rogerio, das hat mit einer kleinen Änderung an deinem Code funktioniert - @Mocked File myDir musste in @Mocked geändert werden (methods = {"list"}) File myDir um es zum Laufen zu bringen. Ich denke, das war vielleicht, weil der Deencapsualtion.invoke-Aufruf vielleicht irgendwann ein reelles File-Objekt benötigt, und alle Methoden zu verspotten schien etwas zu stören. Ich bin ein neuer Benutzer, also kann ich dich nicht abstimmen - sonst würde ich! – user2586917

+1

Großartig! Die Verspottung 'Datei' kann tatsächlich zu unerwarteten Fehlern führen, zumindest in älteren Versionen von JMockit. Ich habe die Antwort mit deinen Änderungen bearbeitet. –

+0

@ Rogério, der obige Weg, ein Mock-Objekt ('myDir') zu erzeugen, führt dazu, dass der Verweis' null' ist, was dazu führt, dass 'myDir.list()' mit einem 'NPE' fehlschlägt. Irgendeine Idee warum? – mystarrocks

0

ausprobieren dieses:

new Expectations {{ 
    invoke(File.class, "list", null, null); 
    returns(files); 
}} 
+1

Danke, aber die Dokumentation sagt invoke ist für den Aufruf einer statischen Methode - list() on Datei ist nicht statisch - scheint nicht zu funktionieren. – user2586917

7

Sie können die setField-Methode aus der Deencapsulation-Klasse verwenden. Beachten Sie folgendes Beispiel: