2011-01-12 16 views
19

Sto cercando di ottenere e invocare un metodo protetto che risiede in una classe diversa e anche un altro pacchetto che utilizza Java Reflection.Accesso al metodo protetto nel test case utilizzando Java Reflection

classe contenente metodo protetto:

package com.myapp; 

public class MyServiceImpl { 

    protected List<String> retrieveItems(String status) { 
     // Implementation 
    } 
} 

classe Calling:

package xxx.myapp.tests; 

import com.myapp.MyServiceImpl; 

public class MyTestCase { 

    List<String> items; 

    public void setUp() throws Exception { 

     MyServiceImpl service = new MyServiceImpl(); 
     Class clazz service.getClass(); 

     // Fails at the next line: 
     Method retrieveItems = clazz.getDeclaredMethod("retrieveItems"); 

     // How to invoke the method and return List<String> items? 
     // tried this but it fails? 
     retrieveItems.invoke(clazz, "S"); 
    } 
} 

Il compilatore genera questa eccezione:

java.lang.NoSuchMethodException: com.myapp.MyServiceImpl.retrieveItems() 

Grazie per aver il tempo di leggere questo.

risposta

23

Il problema con il codice è che la funzione getDeclaredMethod ricerca una funzione per nome e per tipo di argomento. Con la chiamata

Method retrieveItems = clazz.getDeclaredMethod("retrieveItems"); 

Il codice cercherà un metodo retrieveItems() senza argomenti. Il metodo che stai cercando ci vuole un argomento, una stringa, così si dovrebbe chiamare

Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class); 

questo vi dirà Java per cercare retrieveItems(String), che è quello che stai cercando.

+0

+1 - questo è il problema che l'eccezione è segnalazione. Una volta che il metodo è stato recuperato, deve essere reso accessibile secondo la risposta di @jk. –

6

Invece di utilizzare quella roba di riflessione, perché non creare semplicemente una classe derivata, che avrà accesso al metodo protetto?

Vedere Is it bad practice to use Reflection in Unit testing? per ulteriori riflessioni.

+0

+1: questo è un approccio più ragionevole, IMO. –

+1

-1 - non risponde alla domanda radice. Come si accede a un metodo protetto tramite riflessione in Java? – BrainSlugs83

+0

@ BrainSlugs83 Rileggi il titolo della domanda.In realtà l'OP vuole testare del codice, ma pensa erroneamente di dover usare la riflessione. Hanno un problema XY. La mia risposta parla del loro vero problema, non della loro soluzione proposta. – Raedwald

2

se metti la tua casi di test nello stesso package (com.myapp invece di com.myapp.tests) avranno accesso a protette (predefinita livello di pacchetto e) membri.

Quindi è possibile chiamare direttamente service.retrieveMembers(status).

Se si sta tentando di separare la sorgente dai test, solitamente è preferibile utilizzare una directory di origine diversa (ad esempio una directory src e una directory test). è necessaria

+0

Se i test si trovano nello stesso pacchetto, i file di classe compilati si troveranno probabilmente nella stessa directory di destinazione, il che farebbe gonfiare qualsiasi file di implementazione con un gruppo di file di classe di test a meno che non si passi a tutti i pacchetti/progetti che si hanno e definire le regole di esclusione per la directory di destinazione. Non è una buona idea secondo me. –

+0

Ecco perché si utilizza una directory di origine diversa per i test. Questo è il modo standard in cui gli strumenti funzionano come maven. – Nick

+0

Sì, ho frainteso il tuo post. Vedo cosa stai dicendo ora, grazie! –

2

Nessun riflesso o eredità:

Metti la tua MyTestCase sotto pacchettocom.myapp, come scope 'protetto' è anche 'pacchetto'. Quindi MyTestCase può accedere ai metodi protetti di MyServiceImpl.

+0

Se i test si trovano nello stesso pacchetto, probabilmente i file di classe compilati si troveranno nella stessa directory di destinazione, il che farebbe gonfiare qualsiasi file di implementazione con un gruppo di file di classe di test a meno che non si passi a tutti i pacchetti/progetti che si hanno e definire le regole di esclusione per la directory di destinazione. Non è una buona idea secondo me. –

+0

@SandySimonton, può essere raggiunto. Possiamo strutturare il nostro progetto come segue (Maven): 'src-> main-> java' contiene tutto il codice. 'src-> test-> java' contiene tutti i test. –

2

Si dovrebbe usare link per oggetto creato al posto del link alla classe nel metodo Invoke e utilizzare Method.setAccessible (true) invocazione per l'accesso di sblocco:

public void setUp() throws Exception { 
    MyServiceImpl service = new MyServiceImpl(); 
    Class<?> clazz = service.getClass(); 
    Method retrieveItems = clazz.getDeclaredMethod("retrieveItems", String.class); 
    retrieveItems.setAccessible(true); 
    items = (List<String>)retrieveItems.invoke(service, "S"); 
} 
Problemi correlati