2013-07-16 22 views
6

Ho una classe come la seguente;Mock un campo statico privato con 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; 
      } 
     } 
    } 
} 

Quindi, in sostanza, voglio provare questa classe deridendo la classe File in modo che quando la lista() viene chiamato su di esso restituisce una lista di stringhe io definisco nella mia classe di test.

Ho il seguente, ma la sua non funziona al minuto, probabilmente c'è qualcosa di ovvio che sto facendo male - Sono nuovo di JMockit - qualsiasi aiuto è molto apprezzato!

@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" 
    } 

Quando si esegue il test di cui sopra ho un NullPointerException per il campo myDir in ClasseA - in modo che appaia come il suo non farsi deriso correttamente?

risposta

10

JMockit (o qualsiasi altro strumento beffardo) non campi finte o variabili, si deride tipi (classi, interfacce, ecc), dove le istanze di questi tipi ottengono memorizzato all'interno del codice sotto test non è rilevante.

prova Esempio per 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); 
} 

Quanto sopra dovrebbe funzionare. Nota che testare i metodi private direttamente (o accedere ai campi private) è considerato una cattiva pratica, quindi l'ho evitato qui. Inoltre, è meglio evitare di prendere in giro la classe File. Invece, prova solo i tuoi metodi public e usa i file reali invece di prendere in giro il filesystem.

+0

Eccellente, grazie mille per il tuo aiuto Rogerio, questo ha funzionato con una piccola modifica al tuo codice - @Mocked File myDir doveva essere cambiato in @Mocked (methods = {"list"}) File myDir per farlo funzionare. Penso che questo fosse forse perché la chiamata Deencapsualtion.invoke forse ha bisogno di un vero oggetto File ad un certo punto, e prendere in giro tutti i metodi sembra interferire con qualcosa. Sono un nuovo utente quindi non posso votarti - altrimenti lo farei! – user2586917

+1

Ottimo! Mocking 'File' può effettivamente causare errori imprevisti, almeno nelle versioni precedenti di JMockit. Ho modificato la risposta con le tue modifiche. –

+0

@ Rogério, il modo sopra descritto di creare un oggetto mock ('myDir') comporta che il riferimento sia' null', causando che 'myDir.list()' fallisce con un 'NPE'. Qualche idea del perché? – mystarrocks

0

provare questo:

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

Grazie, ma i documenti dicono che invoke serve per invocare un metodo statico - list() su File non è statico - non sembra funzionare. – user2586917

7

È possibile utilizzare il metodo setField dalla classe Deencapsulation. Esempio di esempio:

Deencapsulation.setField(ClassA, "File", your_desired_value); 
Problemi correlati