Variabile protetta e metodo protetto nell'era del TDD [chiuso]

1

Capisco che il metodo protetto sia valido per i test unitari, dal momento che puoi facilmente prendere in giro la classe sovrascrivendo il metodo protetto per il test.

Tuttavia, la variabile protetta è solo una variabile globale (anche se limitata) e dovrebbe essere assolutamente evitata.

Specialmente se hai dichiarato tutto il getter / setter essenziale, dovresti avere una variabile protetta zero e non dovrebbe influire su nient'altro.

Quindi, in futuro, se ho intenzione di eliminare tutte le variabili protette nei miei codici, c'è qualche avvertenza di cui non sono a conoscenza?

    
posta user34401 12.08.2014 - 17:29
fonte

3 risposte

5

Non è necessario testare variabili membro private o protette e i metodi getter / setter sono quasi sempre parte dell'API pubblica, quindi presumo che si stia parlando di test di unità metodi privati o protetti.

Probabilmente questa sarà un'opinione impopolare, ma qui va comunque.

Principio numero uno: se il tuo framework di testing dell'unità non può testare i metodi a meno che non siano pubblici, virtuali o supportati da un'interfaccia, il tuo framework di testing dell'unità fa schifo e devi trovarne uno nuovo .

Ora disponi di un framework di test in grado di testare i metodi privati ...

Principio numero due: Non è necessario prendere in giro un metodo privato. Mai.

Capisci perché? I metodi privati non fanno parte dell'API pubblica della tua classe, quindi prenderli in giro non ha alcun senso.

So che esiste una scuola di pensiero che dice che dovresti rendere pubblici tutti i metodi in modo che possano essere facilmente testati unitamente e che, se il tuo metodo non è pubblico, non è necessario che sia testato su un'unità, perché viene comunque toccato da qualche metodo pubblico.

Hogwash.

Prima di tutto, perché dovrei inquinare la mia API pubblica con metodi che non potrebbero mai essere chiamati direttamente dal consumatore?

In secondo luogo, perché non dovrei essere in grado di testare i miei metodi privati, direttamente? L'intero punto del codice di refactoring in metodi separati è quello di sequestrare la funzionalità dietro quei metodi. I metodi sono una piccola scatola nera testabile e la necessità di crearli e testarli in modo indipendente non diminuisce solo perché li ho contrassegnati come privati.

Non farmi nemmeno iniziare sulla pratica di "una sola interfaccia per ogni classe".

    
risposta data 12.08.2014 - 18:03
fonte
2

Sembra che tu abbia un equivoco che sta portando alla tua confusione.

However, protected variable is just a global variable (although limited) and should be avoided at all.

Un campo protected in una classe ne limita la visibilità alla classe, altre classi nello stesso pacchetto e sottoclassi. Questa è non una variabile globale.

Per avere una variabile 'globale' in Java si avrebbe qualcosa di simile a:

class Foo {
    public static int bar;
}

I punti chiave sono che c'è solo un Foo.bar nel codice ed è accessibile a tutto. La modifica a protected static int bar ne ridurrà la visibilità, ma è ancora qualcosa che è uno stato condiviso globale.

D'altra parte una classe che assomiglia a:

class Foo {
    protected int bar;
}

Questo ha un campo protetto accessibile solo ad alcune cose (come menzionato sopra) ed è una variabile di istanza - che esiste un'istanza per oggetto. Non è una variabile globale. Ci sono buone ragioni per avere un codice simile a questo (lo troverai spesso in classi astratte).

Especially if you've all the essential getter/setter declared, you should have zero protected variable and it should not affect anything else.

I getter e i setter sono diversi dall'accessibilità. Il modello di bean per Java spesso ne determina l'esistenza. In genere, in questo caso si hanno proprietà private anziché protette.

Sebbene indichi nuovamente che un campo protetto è uno di quelli in cui è visibile.

Nel contesto del test ...

Un approccio per rendere metodi specifici restituire un valore specifico è estendere la classe e riscrivere quel metodo. Questo è possibile solo se il metodo non è final o private .

Quindi, sì, potresti davvero usare questo approccio.

Tuttavia, qui c'è disagio nel fatto che devi assicurarti che la tua classe riscritta sia nei pacchetti di prova solo per assicurarti che non scivoli nel tuo codice di rilascio.

L'altra cosa è che quando lo fai, sei molto tentato di scrivere una logica addizionale che differisca sostanzialmente dalla classe estesa. Ciò introduce il pericolo che in realtà non testerai ciò che pensi di testare.

Entrambi questi problemi possono essere risolti prendendo in considerazione la classe nel codice di test e specificando in particolare i valori desiderati. Rende molto chiaro a cosa si sta andando dove senza logica aggiuntiva e che il codice non entra in produzione (le classi derise esistono solo in fase di esecuzione nei test).

Ci sono ancora trucchi da tenere d'occhio qui, perché ancora non ha rimosso la logica (lo ha appena estratto) e tu hai ancora bisogno di assicurarti quella parte funziona correttamente.

Ahh, ma "non puoi prendere in giro o testare facilmente i metodi privati", sottolineano le persone. "Se non puoi farlo facilmente, la gente non lo farà o lo farà male". E questo è vero.

Ma c'è un'altra opzione. La protezione del livello di default in Java. Vedi Controllo dell'accesso ai membri di una classe

package com.se.prog.demo;

class Foo {
    public int bar() { return 42; }
    protected int baz() { return 4; }
    int qux() { return 7; }
    private int xyzzy() { return 13; }
}

I metodi bar , baz e qux possono essere facilmente derisi. qux è accessibile solo da altre classi nello stesso pacchetto di com.se.prog.demo - e tu controlla quell'elenco.

Con la struttura delle directory di maven , si avrebbe

src/main/java/com/se/prog/demo/Foo.java
   ^^^^^^

ma c'è anche

src/test/java/com/se/prog/demo/TestFoo.java
   ^^^^^^

che può accedere a qux() in Foo consentendo il test unitario delle parti più goffe di Foo, senza esporlo al mondo (e alle sottoclassi di Foo).

In alcuni ambienti, questo è considerato un approccio migliore per i metodi che sono le viscere della classe, ma devono ancora essere testati o presi in giro rispetto a quelli protetti o privati.

    
risposta data 12.08.2014 - 18:44
fonte
0

Le variabili protette esistono per una ragione: offrono alle classi genitore la possibilità di far conoscere ai loro figli la loro rappresentazione interna. Se i tuoi metodi get / set pubblici non sono solo pass-through (forse il get / set viene digitato come un DateTime, ma internamente puoi memorizzare tutto come tempo Unix in un campo int, per esempio), quindi le classi che derivano da quel la classe potrebbe aver bisogno di accedere al valore sottostante nel campo, e non quello che l'oggetto espone al mondo esterno (tramite la funzione get).

    
risposta data 12.08.2014 - 17:49
fonte

Leggi altre domande sui tag