Domanda Come posso testare una funzione privata o una classe che ha metodi privati, campi o classi interne?


Come posso testare unitamente (usando xUnit) una classe che ha metodi privati ​​interni, campi o classi nidificate? O una funzione resa privata dall'avere collegamento interno (static in C / C ++) o è in un privato (anonimo) namespace?

Sembra sbagliato cambiare il modificatore di accesso per un metodo o una funzione solo per poter eseguire un test.


2265


origine


risposte:


Se hai un po 'di eredità Giava applicazione, e non ti è permesso di cambiare la visibilità dei tuoi metodi, il modo migliore per testare metodi privati ​​è quello di utilizzare riflessione.

Internamente utilizziamo gli helper per ottenere / impostare private e private static variabili e invocare private e private static metodi. I seguenti schemi ti permetteranno di fare praticamente qualsiasi cosa relativa ai metodi e ai campi privati. Certo che non puoi cambiare private static final variabili attraverso la riflessione.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

E per i campi:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Gli appunti:
  1. targetClass.getDeclaredMethod(methodName, argClasses) ti permette di esaminare private metodi. La stessa cosa vale per    getDeclaredField.
  2. Il setAccessible(true) è richiesto per giocare con i privati.


1416



Il modo migliore per testare un metodo privato è tramite un altro metodo pubblico. Se questo non può essere fatto, allora una delle seguenti condizioni è vera:

  1. Il metodo privato è un codice morto
  2. C'è un odore di progettazione vicino alla classe che stai testando
  3. Il metodo che stai tentando di testare non dovrebbe essere privato

506



Quando ho metodi privati ​​in una classe sufficientemente complicata che sento il bisogno di testare direttamente i metodi privati, questo è un odore di codice: la mia classe è troppo complicata.

Il mio approccio abituale nell'affrontare questi problemi è quello di stuzzicare una nuova classe che contiene i bit interessanti. Spesso, questo metodo e i campi con cui interagisce, e forse un altro metodo o due possono essere estratti in una nuova classe.

La nuova classe espone questi metodi come "pubblici", quindi sono accessibili per i test unitari. Le nuove e le vecchie classi ora sono entrambe più semplici della classe originale, il che è ottimo per me (ho bisogno di mantenere le cose semplici, o mi perdo!).

Nota che non sto suggerendo che le persone creano lezioni senza usare il cervello! Il punto qui è utilizzare le forze dell'unità di test per aiutarti a trovare nuove buone classi.


271



ho usato riflessione per fare questo per Java in passato, e secondo me è stato un grosso errore.

A rigor di termini, dovresti non scrivere test unitari che testano direttamente i metodi privati. Cosa tu dovrebbero essere test è il contratto pubblico che la classe ha con altri oggetti; non dovresti mai testare direttamente le parti interne di un oggetto. Se un altro sviluppatore vuole apportare una piccola modifica interna alla classe, che non influisce sul contratto pubblico delle classi, allora deve modificare il test basato sulla riflessione per assicurarsi che funzioni. Se lo fai ripetutamente durante un progetto, i test unitari smettono di essere un'utile misura della salute del codice, e iniziano a diventare un ostacolo allo sviluppo e un fastidio per il team di sviluppo.

Quello che raccomando di fare invece è utilizzare uno strumento di copertura del codice come Cobertura, per garantire che i test unitari scritti forniscano una copertura decente del codice in metodi privati. In questo modo, verifichi indirettamente cosa stanno facendo i metodi privati ​​e mantieni un livello più alto di agilità.


229



Da questo articolo: Test dei metodi privati ​​con JUnit e SuiteRunner (Bill Venners), in pratica hai 4 opzioni:

  • Non testare metodi privati.
  • Fornire l'accesso al pacchetto metodi.
  • Utilizzare una classe di test annidata.
  • Usa la riflessione.

187



Generalmente un test unitario è destinato all'esercizio dell'interfaccia pubblica di una classe o unità. Pertanto, i metodi privati ​​sono dettagli di implementazione che non ti aspetti di testare esplicitamente.


96



Solo due esempi di dove vorrei testare un metodo privato:

  1. Routine di decodifica - Non vorrei voglio renderli visibili a chiunque per vedere solo per per il test, altrimenti chiunque può usali per decifrare. Ma loro sono intrinseco al codice, complicato, e ha bisogno di lavorare sempre (l'eccezione ovvia è la riflessione che può essere usata per visualizzare anche i metodi privati ​​nella maggior parte dei casi, quando SecurityManager non è configurato per impedirlo).
  2. Creazione di un SDK per la comunità consumo. Qui pubblica prende su a significato completamente diverso, poiché questo è il codice che il mondo intero può vedere (non solo interno alla mia applicazione). metto codice in metodi privati ​​se non lo faccio voglio che gli utenti dell'SDK lo vedano - I non lo vedo come codice odore, semplicemente come funziona la programmazione SDK. Ma di Certo che ho ancora bisogno di testare il mio metodi privati, e sono dove la funzionalità del mio SDK in realtà vite.

Capisco l'idea di testare solo il "contratto". Ma non vedo che uno possa difendere in realtà non testando il codice - il tuo chilometraggio può variare.

Quindi il mio compromesso consiste nel complicare le JUnit con la riflessione, piuttosto che compromettere la sicurezza e l'SDK.


56