Preferiresti rendere le cose private interne / pubbliche per i test, o usare qualche tipo di hack come PrivateObject?

22

Sono abbastanza un principiante nel test del codice, ed ero un pazzo assert prima. Una cosa che mi preoccupa nei test di unità è che spesso è necessario creare public (o almeno internal ) campi che sarebbero stati altrimenti private , per annullare un- readonly , creare private metodi protected virtual invece, ecc ...

Recentemente ho scoperto che puoi evitarlo usando cose come PrivateObject classe per accedere a qualsiasi cosa in un oggetto tramite riflessione. Ma questo rende i tuoi test meno mantenibili (le cose falliscono nell'esecuzione piuttosto che nel tempo di compilazione, saranno interrotte da una semplice rinomina, è più difficile eseguire il debug ...). Qual è la tua opinione su questo ? Quali sono le migliori pratiche nelle prove unitarie relative alla limitazione dell'accesso?

modifica: considera, ad esempio, che hai una classe con una cache in un file su disco, e nei tuoi test vuoi invece scrivere in memoria.

    
posta Zonko 22.12.2011 - 15:12
fonte

5 risposte

35

Non dovresti mai e poi mai

make public (or at least internal) fields that would have been private otherwise, to un-readonly them, make private methods protected virtual instead

Soprattutto la non lettura di un campo può rendere mutevole un oggetto immutabile e sarebbe un disastro.

I tuoi test dovrebbero considerare i tuoi oggetti come scatole nere ( Wikipedia ), il che significa che dovrebbe riguardare solo l'interfaccia pubblica degli oggetti, non i dettagli della loro implementazione.

Se un oggetto non può essere sufficientemente testato usando la sua interfaccia pubblica, è necessario trovare i modi per fornire estensioni formali e utili alla sua interfaccia che facilitino il testing. Ad esempio, un sistema di registrazione con solo una coppia di metodi Register / Deregister potrebbe trarre beneficio da un metodo IsRegistered anche se non è necessario per l'applicazione in questione; tuttavia, si tratta di un'estensione formale e utile dell'interfaccia, che, per inciso, consentirà di eseguire test.

L'importante è che la modifica dell'implementazione dell'oggetto non richieda la modifica del test dell'unità. In teoria dovresti essere in grado di scrivere il test unitario una sola volta e poi chiedere a più programmatori di codificare più implementazioni completamente diverse dell'oggetto da testare per lavorare con il test unitario.

    
risposta data 22.12.2011 - 17:19
fonte
13

In C # puoi utilizzare InternalsVisibleToAttribute per consentire all'assembly di test di visualizzare le classi internal nell'assieme che stai testando. Sembra che tu lo sappia già.

Nella maggior parte dei casi sono interessato solo a testare l'API pubblica del mio assembly. In un caso in cui voglio eseguire il test white box di alcune unità, sposto il codice in una classe internal e lo trasformo in un metodo public di quella classe. Quindi posso codificare un test unitario per quella classe.

Ciò si presta bene all'iniezione di dipendenza e al modello strategico. È possibile astrarre il metodo in un'interfaccia, iniettare l'interfaccia nel costruttore dell'oggetto principale e verificare che i delegati padre siano appropriatamente. Quindi è possibile verificare che l'oggetto figlio si comporti in modo appropriato. Questo rende tutto più modulare.

    
risposta data 22.12.2011 - 15:21
fonte
8

Nella mia esperienza è meglio non esporre gli interni della tua classe appositamente per il test. Anche se questo può sembrare che il test sia più facile da scrivere. Il test è il primo client della tua classe, quindi se è difficile testare la tua classe attraverso la sua interfaccia pubblica, sarà probabilmente difficile usare la tua classe anche in altri posti.

Quanto è facile testare la classe attraverso la sua API pubblica è un feedback su quanto sarà facile da usare la classe. Pensa in parte ai test come a un modo per prototipare l'utilizzo della tua classe.

Cerca di capire perché il test deve rilevare qualcosa sulla classe che non è disponibile tramite l'API pubblica. Forse la tua classe sta facendo troppo e deve invece essere scomposta in un gruppo di classi di cooperazione? Quindi puoi prendere in giro alcune delle classi che collaborano per capire cosa sta facendo la classe sotto test.

Prova ad applicare il principale dell'inversione di dipendenza e a introdurre interfacce tra le tue classi che puoi prendere in giro test. Puoi fornire ai collaboratori il tuo test utilizzando inversione del controllo .

Prendi in considerazione anche l'applicazione del "tell do not ask" principal per aiutare a strutturare l'interfaccia di classe in un robusto , in modo approssimativo, in cui le informazioni giuste sono esposte e il resto è nascosto.

    
risposta data 22.12.2011 - 17:34
fonte
6

Personalmente preferisco lasciare il codice che sto testando nel modo più puro possibile e se il codice di test ha bisogno di hack (e in puntatori brutti di C ++, ecc.) sono felice di farlo.

    
risposta data 22.12.2011 - 15:44
fonte
5

La visibilità del tuo codice non ha nulla a che fare con i tuoi test unitari!

Rendi i tuoi metodi privati non allo scopo di nasconderli dai test e non li rendi pubblici da esporre per i test, giusto? Questa è la tua implementazione essenziale qui, non i test, quei server come prova del tuo codice, ma non sono il tuo codice .

Esistono molti modi per abilitare l'accesso a metodi e proprietà nascosti (privati o interni). Molti framework di test e IDE (ad esempio, Visual Studio) ti supportano qui generando tutto il necessario per l'accesso, devi solo creare i tuoi casi di test. Quindi, perché preoccuparsi? Meglio mantenere il tuo codice pulito e pulito.

    
risposta data 22.12.2011 - 16:58
fonte

Leggi altre domande sui tag