Devo testare metodi privati ​​o solo pubblici?

Ho letto questo post su come testare metodi privati. Di solito non li test, perché ho sempre pensato che fosse più veloce testare solo metodi pubblici che verranno chiamati dall’esterno dell’object. Metti alla prova metodi privati? Dovrei sempre provarli?

Non collaudo unitamente metodi privati. Un metodo privato è un dettaglio di implementazione che dovrebbe essere nascosto agli utenti della class. Il test dei metodi privati ​​interrompe l’incapsulamento.

Se trovo che il metodo privato è enorme, complesso o abbastanza importante da richiedere i propri test, lo metto in un’altra class e lo renderò pubblico lì ( Method Object ). Quindi posso facilmente testare il metodo precedentemente privato-ma-ora-pubblico che ora vive sulla sua stessa class.

Qual è lo scopo del test?

La maggior parte delle risposte finora afferma che i metodi privati ​​sono dettagli di implementazione che non hanno (o almeno non dovrebbero) importanza finché l’interfaccia pubblica è ben collaudata e funzionante. Questo è assolutamente corretto se il tuo unico scopo per i test è quello di garantire che l’interfaccia pubblica funzioni .

Personalmente, il mio uso principale per i test di codice è quello di garantire che le future modifiche al codice non causino problemi e per aiutare i miei sforzi di debug, se lo fanno. Trovo che testare i metodi privati ​​con la stessa cura con cui l’interfaccia pubblica (se non di più!) Promuova questo scopo.

Considera: hai un metodo pubblico A che chiama il metodo privato B. A e B entrambi fanno uso del metodo C. C è cambiato (forse da te, forse da un venditore), causando il fallimento di A dei test. Non sarebbe utile avere anche i test per B, anche se è privato, in modo da sapere se il problema è nell’uso di C, nell’uso di C di C o in entrambi?

Il test dei metodi privati ​​aggiunge valore anche nei casi in cui la copertura del test dell’interfaccia pubblica è incompleta. Mentre questa è una situazione che in genere vogliamo evitare, il test dell’unità di efficienza dipende sia dai test che individuano i bug sia dai costi di sviluppo e manutenzione associati a tali test. In alcuni casi, i benefici della copertura del test del 100% possono essere giudicati insufficienti per giustificare i costi di tali test, producendo lacune nella copertura del test dell’interfaccia pubblica. In questi casi, un test ben mirato di un metodo privato può essere un’aggiunta molto efficace al codice base.

Tendo a seguire i consigli di Dave Thomas e Andy Hunt nel loro libro Pragmatic Unit Testing :

In generale, non vuoi rompere alcun incapsulamento per motivi di test (o come diceva la mamma, “non esporre i tuoi dati personali!”). Il più delle volte, dovresti essere in grado di testare una class esercitando i suoi metodi pubblici. Se c’è una funzionalità significativa nascosta dietro l’accesso privato o protetto, questo potrebbe essere un segnale di avvertimento che c’è un’altra class in là che fatica a uscire.

Ma a volte non riesco a impedirmi di testare metodi privati ​​perché mi dà il senso di rassicurazione che sto costruendo un programma completamente robusto.

Mi sento in qualche modo obbligato a testare le funzioni private mentre sto seguendo sempre di più una delle nostre ultime raccomandazioni di QA nel nostro progetto:

Non più di 10 nella complessità ciclomatica per funzione.

Ora l’effetto collaterale dell’attuazione di questa politica è che molte delle mie grandi funzioni pubbliche vengono divise in molte funzioni private più focalizzate e meglio chiamate.
La funzione pubblica è ancora lì (ovviamente) ma è essenzialmente ridotta a chiamare tutte quelle “sotto-funzioni” private

Questo è davvero interessante, perché il callstack ora è molto più facile da leggere (invece di un bug all’interno di una funzione di grandi dimensioni, ho un bug in una sotto-funzione secondaria con il nome delle funzioni precedenti nel callstack per aiutarmi a capire ‘come ci sono arrivato’)

Tuttavia, ora sembra più facile testare direttamente le funzioni private e lasciare che il test della funzione pubblica di grandi dimensioni sia sottoposto a una sorta di test di “integrazione” in cui uno scenario deve essere affrontato.

Solo i miei 2 centesimi.

Sì, eseguo il test delle funzioni private, perché anche se sono testate con i metodi pubblici, è bello in TDD (Test Driven Design) per testare la parte più piccola dell’applicazione. Ma le funzioni private non sono accessibili quando sei nella tua class di unità di prova. Ecco cosa facciamo per testare i nostri metodi privati.

Perché abbiamo metodi privati?

Le funzioni private esistono principalmente nella nostra class perché vogliamo creare codice leggibile nei nostri metodi pubblici. Non vogliamo che l’utente di questa class chiami questi metodi direttamente, ma attraverso i nostri metodi pubblici. Inoltre, non vogliamo modificare il loro comportamento durante l’estensione della class (in caso di protezione), quindi è un privato.

Quando codifichiamo, utilizziamo il test-driven-design (TDD). Ciò significa che a volte ci imbattiamo in una funzionalità privata e che vogliamo testare. Le funzioni private non sono testabili in phpUnit, perché non possiamo accedervi nella class Test (sono private).

Pensiamo che ci sono 3 soluzioni:

1. Puoi testare i tuoi dati personali attraverso i tuoi metodi pubblici

vantaggi

  • Test di unità semplice (non sono necessari “hack”)

svantaggi

  • Il programmatore deve capire il metodo pubblico, mentre vuole solo testare il metodo privato
  • Non stai testando la minima parte testabile dell’applicazione

2. Se il privato è così importante, forse è un codice per creare una nuova class separata per esso

vantaggi

  • Puoi refactoring in una nuova class, perché se è così importante, anche altre classi potrebbero averne bisogno
  • L’unità testabile è ora un metodo pubblico, quindi verificabile

svantaggi

  • Non è necessario creare una class se non è necessaria e utilizzata solo dalla class da cui proviene il metodo
  • Potenziale perdita di prestazioni a causa di sovraccarico aggiunto

3. Modificare il modificatore di accesso su (finale) protetto

vantaggi

  • Stai testando la più piccola parte testabile dell’applicazione. Quando si utilizza la protezione finale, la funzione non sarà sovrascrivibile (proprio come un privato)
  • Nessuna perdita di prestazioni
  • Nessun sovraccarico extra

svantaggi

  • Stai modificando un accesso privato a protetto, il che significa che è accessibile dai suoi figli
  • Hai ancora bisogno di una class Mock nella tua class di test per usarla

Esempio

 class Detective { public function investigate() {} private function sleepWithSuspect($suspect) {} } Altered version: class Detective { public function investigate() {} final protected function sleepWithSuspect($suspect) {} } In Test class: class Mock_Detective extends Detective { public test_sleepWithSuspect($suspect) { //this is now accessible, but still not overridable! $this->sleepWithSuspect($suspect); } } 

Quindi la nostra unità di test può ora chiamare test_sleepWithSuspect per testare la nostra precedente funzione privata.

Penso che sia meglio testare semplicemente l’interfaccia pubblica di un object. Dal punto di vista del mondo esterno, solo il comportamento dell’interfaccia pubblica è importante e questo è ciò a cui i vostri test unitari dovrebbero essere diretti.

Una volta che hai scritto dei test di unità solidi scritti per un object, non vuoi tornare indietro e cambiare quei test solo perché l’implementazione dietro l’interfaccia è cambiata. In questa situazione, hai rovinato la coerenza dei tuoi test unitari.

Se il metodo privato è ben definito (cioè, ha una funzione testabile e non è destinato a cambiare nel tempo) allora sì. Metto alla prova tutto ciò che è testabile dove ha senso.

Ad esempio, una libreria di crittografia potrebbe hide il fatto che esegue la crittografia a blocchi con un metodo privato che crittografa solo 8 byte alla volta. Vorrei scrivere un test unitario per questo – non è destinato a cambiare, anche se è nascosto, e se si rompe (a causa di miglioramenti delle prestazioni futuri, per esempio), allora voglio sapere che è la funzione privata che si è rotta, non solo che una delle funzioni pubbliche si ruppe.

Velocizza il debug in seguito.

-Adamo

Se il tuo metodo privato non viene testato chiamando i tuoi metodi pubblici, allora che cosa sta facendo? Sto parlando privato non protetto o amico.

Se stai sviluppando un test guidato (TDD), testerai i tuoi metodi privati.

Non mi piace testare le funzionalità private per un paio di motivi. Sono come segue (questi sono i punti principali per le persone TLDR):

  1. In genere quando sei tentato di testare il metodo privato di una class, è un odore di design.
  2. Puoi testarli attraverso l’interfaccia pubblica (che è il modo in cui vuoi testarli, perché è così che il client li chiamerà / li userà). Puoi ottenere un falso senso di sicurezza vedendo la luce verde su tutti i test di passaggio per i tuoi metodi privati. È molto meglio / più sicuro testare i casi limite sulle tue funzioni private tramite la tua interfaccia pubblica.
  3. Si rischia una duplicazione test severa (test che sembrano molto simili) testando metodi privati. Ciò ha conseguenze importanti quando i requisiti cambiano, poiché molti più test del necessario si romperanno. Può anche metterti in una posizione in cui è difficile refactoring a causa della tua suite di test … che è l’ironia finale, perché la suite di test è lì per aiutarti a riprogettazione e refactoring in sicurezza!

Spiegherò ognuno di questi con un esempio concreto. Si scopre che 2) e 3) sono in qualche modo complicatamente connessi, quindi il loro esempio è simile, anche se li considero separati perché non si dovrebbero testare metodi privati.

C’è una volta che considero opportuno testare metodi privati, ma ho intenzione di esaminarlo più in dettaglio più avanti.

Vado anche oltre perché TDD non è una scusa valida per testare metodi privati ​​alla fine.

Refactoring la tua via d’uscita da un cattivo design

Uno dei più comuni (anti) paterni che vedo è quello che Michael Feathers definisce una class “Iceberg” (se non sai chi è Michael Feathers, vai a comprare / leggi il suo libro “Lavorare efficacemente con il codice legacy”. una persona che vale la pena conoscere se sei un ingegnere / sviluppatore software professionista. Ci sono altri (anti) schemi che fanno sorgere questo problema, ma questo è di gran lunga il più comune in cui mi sono imbattuto. Le classi “Iceberg” hanno un metodo pubblico e il resto è privato (motivo per cui è allettante testare i metodi privati). Si chiama class “Iceberg” perché di solito c’è un metodo pubblico solitario, ma il resto della funzionalità è nascosto sott’acqua sotto forma di metodi privati. Potrebbe sembrare qualcosa del genere:

Valutatore di regole

Ad esempio, è ansible testare GetNextToken() chiamandolo su una stringa in successione e vedendo che restituisce il risultato previsto. Una funzione come questa garantisce un test: quel comportamento non è banale, specialmente se le tue regole di tokenizzazione sono complesse. Facciamo finta che non sia tutto così complesso, e vogliamo solo mettere in fila i token delimitati dallo spazio. Quindi scrivi un test, forse è qualcosa di simile a questo (un linguaggio agno-psico-codice, spero che l’idea sia chiara):

 TEST_THAT(RuleEvaluator, canParseSpaceDelimtedTokens) { input_string = "1 2 test bar" re = RuleEvaluator(input_string); ASSERT re.GetNextToken() IS "1"; ASSERT re.GetNextToken() IS "2"; ASSERT re.GetNextToken() IS "test"; ASSERT re.GetNextToken() IS "bar"; ASSERT re.HasMoreTokens() IS FALSE; } 

Beh, sembra davvero carino. Vorremmo essere sicuri di mantenere questo comportamento mentre apportiamo modifiche. Ma GetNextToken() è una funzione privata ! Quindi non possiamo testarlo in questo modo, perché non verrà nemmeno compilato (supponendo che stiamo usando un linguaggio che impone effettivamente pubblico / privato, a differenza di alcuni linguaggi di scripting come Python). Ma che dire della modifica della class RuleEvaluator per seguire il Principio della singola responsabilità (Principio della singola responsabilità)? Ad esempio, sembra che un parser, un tokenizer e un valutatore si siano inceppati in una class. Non sarebbe meglio semplicemente separare queste responsabilità? Inoltre, se si crea una class Tokenizer , i metodi pubblici sarebbero HasMoreTokens() e GetNextTokens() . La class RuleEvaluator potrebbe avere un object Tokenizer come membro. Ora, possiamo mantenere lo stesso test di cui sopra, tranne che stiamo testando la class Tokenizer posto della class RuleEvaluator .

Ecco come potrebbe apparire in UML:

Valutatore di regole refactored

Nota che questo nuovo design aumenta la modularità, quindi potresti potenzialmente riutilizzare queste classi in altre parti del tuo sistema (prima di non poterlo fare, i metodi privati ​​non sono riutilizzabili per definizione). Questo è il vantaggio principale di abbattere il RuleEventore, insieme a una maggiore comprensibilità / località.

Il test risulterebbe estremamente simile, tranne per il fatto che verrà compilato questa volta poiché il metodo GetNextToken() è ora pubblico sulla class Tokenizer :

 TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens) { input_string = "1 2 test bar" tokenizer = Tokenizer(input_string); ASSERT tokenizer.GetNextToken() IS "1"; ASSERT tokenizer.GetNextToken() IS "2"; ASSERT tokenizer.GetNextToken() IS "test"; ASSERT tokenizer.GetNextToken() IS "bar"; ASSERT tokenizer.HasMoreTokens() IS FALSE; } 

Test dei componenti privati ​​tramite un’interfaccia pubblica ed evitare la duplicazione dei test

Anche se non pensi di poter abbattere il tuo problema in un numero inferiore di componenti modulari (il 95% delle volte puoi provare a farlo), puoi semplicemente testare le funzioni private tramite un’interfaccia pubblica. Molte volte i membri privati ​​non valgono la pena di essere testati perché saranno testati attraverso l’interfaccia pubblica. Molte volte quello che vedo sono test che sembrano molto simili, ma testano due diverse funzioni / metodi. Quello che finisce per accadere è che quando cambiano i requisiti (e lo fanno sempre), ora hai 2 test non funzionanti invece di 1. E se hai davvero testato tutti i tuoi metodi privati, potresti avere più di 10 test non funzionanti invece di 1. In breve testare le funzioni private (utilizzando FRIEND_TEST o renderle pubbliche o utilizzando la reflection) che potrebbero essere altrimenti testate tramite un’interfaccia pubblica può causare la duplicazione del test . Davvero non vuoi questo, perché niente fa più male della tua suite di test che ti rallenta. Dovrebbe ridurre i tempi di sviluppo e ridurre i costi di manutenzione! Se si testano metodi privati ​​che sono altrimenti testati attraverso un’interfaccia pubblica, la suite di test potrebbe benissimo fare il contrario e aumentare triggersmente i costi di manutenzione e aumentare i tempi di sviluppo. Quando rendi pubblica una funzione privata, o se usi qualcosa come FRIEND_TEST e / o reflection, di solito finirai per rimpiangerlo a lungo termine.

Considerare la seguente ansible implementazione della class Tokenizer :

inserisci la descrizione dell'immagine qui

Diciamo che SplitUpByDelimiter() è responsabile della restituzione di un array in modo tale che ogni elemento dell’array sia un token. Inoltre, diciamo semplicemente che GetNextToken() è semplicemente un iteratore su questo vettore. Quindi il tuo test pubblico potrebbe sembrare questo:

 TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens) { input_string = "1 2 test bar" tokenizer = Tokenizer(input_string); ASSERT tokenizer.GetNextToken() IS "1"; ASSERT tokenizer.GetNextToken() IS "2"; ASSERT tokenizer.GetNextToken() IS "test"; ASSERT tokenizer.GetNextToken() IS "bar"; ASSERT tokenizer.HasMoreTokens() IS false; } 

Facciamo finta di avere quello che Michael Feather chiama uno strumento per tastare . Questo è uno strumento che ti consente di toccare parti private di altre persone. Un esempio è FRIEND_TEST di googletest o reflection se il linguaggio lo supporta.

 TEST_THAT(TokenizerTest, canGenerateSpaceDelimtedTokens) { input_string = "1 2 test bar" tokenizer = Tokenizer(input_string); result_array = tokenizer.SplitUpByDelimiter(" "); ASSERT result.size() IS 4; ASSERT result[0] IS "1"; ASSERT result[1] IS "2"; ASSERT result[2] IS "test"; ASSERT result[3] IS "bar"; } 

Bene, ora diciamo che i requisiti cambiano e la tokenizzazione diventa molto più complessa. Decidi che un semplice delimitatore di stringhe non è sufficiente, e hai bisogno di una class di Delimiter per gestire il lavoro. Naturalmente, ti aspetteresti un test da rompere, ma quel dolore aumenta quando testi le funzioni private.

Quando è ansible testare metodi privati ​​appropriati?

Non c’è “una taglia unica” nel software. A volte va bene (e in realtà è ideale) “infrangere le regole”. Sostengo fortemente di non testare le funzionalità private quando è ansible. Ci sono due situazioni principali quando penso che sia okay:

  1. Ho lavorato molto con i sistemi legacy (motivo per cui sono un grande fan di Michael Feathers) e posso tranquillamente dire che a volte è semplicemente più sicuro testare semplicemente la funzionalità privata. Può essere particolarmente utile per ottenere “prove di caratterizzazione” nella linea di base.

  2. Sei di fretta e devi fare la cosa più veloce ansible per qui e ora. A lungo termine, non si desidera testare metodi privati. Ma dirò che di solito ci vuole del tempo per il refactoring per affrontare i problemi di progettazione. E a volte devi spedire in una settimana. Va bene: fai il veloce e sporco e prova i metodi privati ​​usando uno strumento per tentare se questo è quello che pensi sia il modo più veloce e più affidabile per portare a termine il lavoro. Ma capisci che quello che hai fatto è stato non ottimale nel lungo periodo, e per favore considera di tornare ad esso (o, se è stato dimenticato ma lo vedi dopo, aggiustalo).

Ci sono probabilmente altre situazioni in cui va bene. Se pensi che sia ok, e hai una buona giustificazione, allora fallo. Nessuno ti sta fermando. Basta essere consapevoli dei costi potenziali.

La scusa TDD

Per inciso, non mi piace che le persone usino il TDD come scusa per testare metodi privati. Pratico TDD e non credo che TDD ti costringa a farlo. È ansible scrivere prima il test (per la propria interfaccia pubblica) e quindi scrivere il codice per soddisfare tale interfaccia. A volte scrivo un test per un’interfaccia pubblica e lo soddisfo scrivendo uno o due metodi privati ​​più piccoli (ma non provo direttamente i metodi privati, ma so che funzionano o il mio test pubblico non funzionerà ). Se ho bisogno di testare casi limite di quel metodo privato, scriverò un sacco di test che li colpiranno attraverso la mia interfaccia pubblica. Se non riesci a capire come colpire i casi limite, questo è un segno forte che devi refactoring in piccoli componenti ciascuno con i propri metodi pubblici. È un segno che le tue funzioni private stanno facendo troppo, e al di fuori dello scopo della class .

Inoltre, a volte trovo di scrivere un test che è troppo grande per mordere al momento, e quindi penso “eh tornerò a quel test più tardi, quando avrò più API per lavorare con” (I lo commenterò e lo terrò in mente). È qui che molti sviluppatori che ho incontrato inizieranno a scrivere test per le loro funzionalità private, usando TDD come capro espiatorio. Dicono “oh, beh, ho bisogno di qualche altro test, ma per scrivere quel test, avrò bisogno di questi metodi privati, quindi, dato che non posso scrivere alcun codice di produzione senza scrivere un test, devo scrivere un test per un metodo privato. ” Ma quello che devono veramente fare è rifattorizzare in componenti più piccoli e riutilizzabili invece di aggiungere / testare una serie di metodi privati ​​alla loro attuale class.

Nota:

Ho risposto a una domanda simile sull’esperimento dei metodi privati ​​utilizzando GoogleTest poco fa. Ho modificato per lo più questa risposta per essere più indipendente dal linguaggio qui.

PS Ecco la lezione pertinente sulle classi di iceberg e gli strumenti per il groping di Michael Feathers: https://www.youtube.com/watch?v=4cVZvoFGJTU

Non sono un esperto in questo campo, ma i test unitari dovrebbero testare il comportamento, non l’implementazione. I metodi privati ​​sono strettamente parte dell’implementazione, quindi IMHO non dovrebbe essere testato.

Noi testiamo i metodi privati ​​per deduzione, intendendo con ciò che cerchiamo una copertura totale del test di class di almeno il 95%, ma solo che i nostri test chiamano in metodi pubblici o interni. Per ottenere la copertura, è necessario effettuare più chiamate al pubblico / interne in base ai diversi scenari che possono verificarsi. Ciò rende i nostri test più attenti allo scopo del codice che stanno testando.

La risposta di Trumpi al post che hai collegato è la migliore.

Test unitari che ritengo siano per testare metodi pubblici. I tuoi metodi pubblici usano i tuoi metodi privati, quindi anche indirettamente vengono testati.

Sto soffocando su questo problema da un po ‘di tempo soprattutto con il provare la mia mano al TDD.

Mi sono imbattuto in due post che penso affrontino questo problema a fondo nel caso di TDD.

  1. Test di metodi privati, TDD e refactoring basato su test
  2. Lo sviluppo basato sui test non sta testando

In sintesi:

  • Quando si utilizzano tecniche di sviluppo (progettazione) test driven, i metodi privati ​​dovrebbero sorgere solo durante il processo di ri-factoring di codice già funzionante e testato.

  • Per la natura stessa del processo, qualsiasi funzionalità di implementazione semplice estratta da una funzione completamente testata sarà autodiagnosticata (copertura di test indiretta).

Per me sembra abbastanza chiaro che all’inizio della codifica molti metodi saranno funzioni di livello superiore perché incapsulano / descrivono il progetto.

Pertanto, questi metodi saranno pubblici e testarli sarà abbastanza facile.

I metodi privati ​​verranno più tardi una volta che tutto funziona bene e stiamo rielaborando per motivi di leggibilità e pulizia .

Come citato sopra, “Se non metti alla prova i tuoi metodi privati, come fai a sapere che non si romperanno?”

Questo è un grosso problema. Uno dei punti salienti dei test unitari è sapere dove, quando e come qualcosa si è rotto al più presto. Riducendo così una quantità significativa di sforzi di sviluppo e controllo qualità. Se tutto ciò che viene testato è pubblico, allora non hai una copertura e una delineazione oneste degli interni della class.

Ho trovato uno dei modi migliori per farlo è semplicemente aggiungere il riferimento di test al progetto e mettere i test in una class parallela ai metodi privati. Inserire la logica di compilazione appropriata in modo che i test non si integrino nel progetto finale.

Quindi hai tutti i vantaggi di testare questi metodi e puoi trovare problemi in pochi secondi o minuti o ore.

Quindi, in sintesi, sì, unit test i tuoi metodi privati.

Se non metti alla prova i tuoi metodi privati, come fai a sapere che non si romperanno?

Non dovresti . Se i tuoi metodi privati ​​hanno abbastanza complessità che devono essere testati, dovresti metterli su un’altra class. Mantenere un’elevata coesione , una class dovrebbe avere un solo scopo. L’interfaccia pubblica di class dovrebbe essere sufficiente.

È ovviamente dipendente dalla lingua. In passato con c ++, ho dichiarato che la class di test era una class di amici. Sfortunatamente, ciò richiede che il codice di produzione conosca la class di test.

Comprendo il punto di vista in cui i metodi privati ​​sono considerati dettagli di implementazioni e quindi non devono essere testati. E vorrei attenermi a questa regola se dovessimo svilupparci solo al di fuori dell’object. Ma noi, siamo una specie di sviluppatori con restrizioni che si stanno sviluppando solo al di fuori degli oggetti, chiamando solo i loro metodi pubblici? Oppure stiamo anche sviluppando questo object? Dato che non siamo tenuti a programmare oggetti esterni, probabilmente dovremo chiamare quei metodi privati ​​in quelli pubblici che stiamo sviluppando. Non sarebbe bello sapere che il metodo privato resiste a tutte le probabilità?

I know some people could answer that if we are developing another public method into that object then this one should be tested and that’s it (the private method could carry on living without test). But this is also true for any public methods of an object: when developing a web app, all the public methods of an object are called from controllers methods and hence could be considered as implementation details for controllers.

So why are we unit testing objects? Because it is really difficult, not to say impossible to be sure that we are testing the controllers’ methods with the appropriate input which will trigger all the branches of the underlying code. In other words, the higher we are in the stack, the more difficult it is to test all the behaviour. And so is the same for private methods.

To me the frontier between private and public methods is a psychologic criteria when it comes to tests. Criteria which matters more to me are:

  • is the method called more than once from different places?
  • is the method sophisticated enough to require tests?

If we test to ensure the correctness of the logic, and a private method is carrying a logic, we should test it. Isn’t it? So why are we going to skip that?

Writing tests based on the visibility of methods is completely irrelevant idea.

If I find that the private method is huge or complex or important enough to require its own tests, I just put it in another class and make it public there (Method Object). Then I can easily test the previously private but now public method that now lives on its own class.

If the method is significant enough/complex enough , I’ll usually make it “protected” and test it. Some methods will be left private and tested implicitly as part of unit tests for the public/protected methods.

Absolutely YES. That is the point of Unit testing, you test Units. Private method is a Unit. Without testing private methods TDD (Test Driven Development) would be impossible,

I see many people are in the same line of thinking: test at the public level. but isn’t that what our QA team does? They test input and expected output. If as developers we only test the public methods then we are simply redoing QA’s job and not adding any value by “unit testing”.

The answer to “Should I test private methods?” is “…….sometimes”. Typically you should be testing against the interface of your classs.

  • One of the reasons is because you do not need double coverage for a feature.
  • Another reason is that if you change private methods, you will have to update each test for them, even if the interface of your object hasn’t changed at all.

Ecco un esempio:

 class Thing def some_string one + two end private def one 'aaaa' end def two 'bbbb' end end class RefactoredThing def some_string one + one_a + two + two_b end private def one 'aa' end def one_a 'aa' end def two 'bb' end def two_b 'bb' end end 

In RefactoredThing you now have 5 tests, 2 of which you had to update for refactoring, but your object’s functionality really hasn’t changed. So let’s say that things are more complex than that and you have some method that defines the order of the output such as:

 def some_string_positioner if some case elsif other case elsif other case elsif other case else one more case end end 

This shouldn’t be run by an outside user, but your encapsulating class may be to heavy to run that much logic through it over and over again. In this case maybe you would rather extract this into a seperate class, give that class an interface and test against it.

And finally, let’s say that your main object is super heavy, and the method is quite small and you really need to ensure that the output is correct. You are thinking, “I have to test this private method!”. Have you that maybe you can make your object lighter by passing in some of the heavy work as an initialization parameter? Then you can pass something lighter in and test against that.

No You shouldn’t test the Private Methods why? and moreover the popular mocking framework such as Mockito doesn’t provide support for testing private methods.