2013-03-24 10 views
11

Sto usando JMockit 1.1 e tutto ciò che voglio fare è richiamare un metodo privato e testare il valore restituito. Tuttavia, ho difficoltà a capire esattamente come farlo dall'esempio JMockit De-Encapsulation.Invocazione di un metodo privato tramite JMockit per verificare il risultato

Il metodo che sto cercando di testare è il metodo privato in questa classe:

public class StringToTransaction { 
    private List<String> parseTransactionString(final String input) { 
     // .. processing 
     return resultList; 
    } 
} 

E il mio codice di prova è inferiore.

@Test 
public void testParsingForCommas() { 
    final StringToTransaction tested = new StringToTransaction(); 
    final List<String> expected = new ArrayList<String>(); 
    // Add expected strings list here.. 
    new Expectations() { 
     { 
     invoke(tested, "parseTransactionString", "blah blah"); 
     returns(expected); 
     } 
    }; 
} 

E l'errore che sto ottenendo è:

java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter

Forse mi hanno frainteso l'intera API qui, perché non credo di voler deridere la classe .. basta verificare il risultato di chiamando il metodo privato.

risposta

25

Penso che lo stiate facendo troppo complicato. Non dovresti usare affatto il blocco Expectations. Tutto quello che devi fare è qualcosa di simile:

@Test 
public void testParsingForCommas() { 
    StringToTransaction tested = new StringToTransaction(); 
    List<String> expected = new ArrayList<String>(); 
    // Add expected strings list here.. 

    List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah"); 
    assertEquals(expected, actual); 
} 

In sostanza, chiamare un metodo privato tramite Deencapsulation e test che il reale è uguale al previsto. Proprio come faresti se il metodo fosse pubblico. Non si sta facendo il mocking, quindi non è necessario alcun blocco di Expectations.

+0

Ciao @JeffOlson - su quale classe è il metodo invoke()? Su Expectations, invoke() è un metodo di istanza protetto. O forse basta usare java.lang.reflect.Method.invoke() e ignorare completamente JMockit .. –

+0

Finalmente capisco ... è 'Deencapsulation.invoke', grazie a @JeffOlson e grazie a Rogerio in https: // groups. google.com/d/msg/jmockit-users/oEgjW0DfmgU/3pEE1mjt1ncJ. –

+0

Sì, è corretto. Scusa per non essere più chiaro, ma hai usato 'invoke()' direttamente nel tuo esempio iniziale (presumibilmente tramite un'importazione statica), quindi ho pensato di lasciarlo così com'è. Aggiornerò la mia risposta per essere più chiara per chiunque altro possa leggere questo in futuro. –

0

Perché si desidera testare direttamente il metodo privato? La maggior parte delle volte i metodi API, ad esempio i metodi di interfaccia pubblica, sono testati come , i metodi privati ​​verranno testati indirettamente anche con lo. È possibile inserire le istruzioni di asserzione con i valori previsti dai metodi privati ​​ in cui li si chiama nei metodi pubblici. Quindi, se l'affermazione fallisce, sei sicuro che ci sia qualche problema con il metodo privato. Quindi non è necessario testarlo separatamente.

+0

Ciao @Ankur, mi scuso, ma sto cercando una risposta che riguarda come utilizzare correttamente JMockit in questa situazione (o anche se posso farlo). Non sto cercando di discutere perché dovrei o non dovrei provare un metodo privato. Capisco che usare le asserzioni tramite metodi pubblici sia un altro modo per farlo, ma non è quello che sto cercando di risolvere qui. –

+0

Dai un'occhiata a questo: http://stackoverflow.com/questions/5729973/jmockit-two-mocked-instances-of-the-same-type –

+0

Posso essere un po 'denso @Ankur ma non riesco a capire come applica questa soluzione al mio problema. :) Mettendo il blocco ** Expectations ** prima dell'inizializzazione di ** tested **, si ottiene un errore di compilazione: ** testato non può essere risolto con una variabile **. –

2

A questo punto, non so se JMockit può o deve essere utilizzato per questo. Il test del mio metodo privato può essere fatto con una semplice riflessione vecchia, anche se ho iniziato questo esercizio per conoscere JMockit (e testare il mio codice). Nel caso in cui JMockit non possa essere usato per questo, ecco come posso usare la riflessione.

@Test 
public void testParsingForCommas() throws Exception { 
    StringToTransaction tested = new StringToTransaction(); 
    ArrayList<String> expected = new ArrayList<>(); 
    expected.add("Test"); 

    Method declaredMethod = 
     tested.getClass().getDeclaredMethod("parseTransactionString", 
       String.class); 
    declaredMethod.setAccessible(true); 
    Object actual = declaredMethod.invoke(tested, "blah blah"); 
    assertEquals(expected, actual); 
} 

La chiamata a setAccessible(true) è importante qui o la invoke farà saltare in aria quando si chiama un metodo privato.

declaredMethod.setAccessible(true); 

Ma vuoi sapere cosa è veramente bello? Se non chiami setAccessible(true), esploderà con un java.lang.StackOverflowError! :)

Problemi correlati