Come posso sostenere i test unitari su codice privato?

15

Sto cercando di sostenere i test unitari nel mio gruppo di lavoro, ma un'obiezione che spesso ottengo è che dovrebbe essere usata solo per le API esportate esternamente (che è solo una parte minima e non critica del nostro sistema), e non su codice interno e privato (che ora ha solo test funzionali).

Mentre penso che il test unitario possa e debba essere applicato a tutto il codice, come posso convincere i miei colleghi?

    
posta Wizard79 10.10.2010 - 14:38
fonte

7 risposte

9

I tuoi colleghi potrebbero confondere i veri test unitari con i test di integrazione. Se il tuo prodotto è (o ha) un'API, i test di integrazione possono essere programmati come casi di test NUnit. Alcune persone credono erroneamente che si tratti di test unitari.

Puoi provare a convincere i tuoi colleghi con quanto segue (sono sicuro che già conosci questa roba, tutto quello che sto dicendo è che indicarlo ai tuoi colleghi potrebbe aiutare):

  • Copertura del test . Misurare la percentuale effettiva di copertura del test di quei test di integrazione. Questo è un test di realtà per coloro che non hanno mai eseguito la copertura di test. Poiché è difficile esercitare tutti i percorsi logici quando l'input è a diversi livelli di distanza, la copertura del test supera in alto tra il 20% e il 50%. Per avere più copertura, i tuoi colleghi devono scrivere test unitari reali e isolati.
  • Configurazione . Distribuisci lo stesso software sotto test e forse puoi dimostrare ai tuoi collaboratori quanto sia difficile eseguire i test in un ambiente diverso. Percorsi per vari file, stringhe di connessione DB, URL di servizi remoti, ecc. - tutto sommato.
  • Tempo di esecuzione . A meno che i test non siano veri test unitari e possano essere eseguiti in memoria, impiegheranno molto tempo per essere eseguiti.
risposta data 11.10.2010 - 04:32
fonte
12

Le ragioni per utilizzare i test unitari su codice interno / privato sono esattamente le stesse delle API supportate esternamente:

  • Impediscono che i bug si ripetano (i test unitari fanno parte della tua suite di test di regressione).
  • Documentano (in un formato eseguibile!) che il codice funziona.
  • Forniscono una definizione eseguibile di cosa significa "il codice funziona".
  • Forniscono un mezzo automatico per dimostrare che il codice corrisponde effettivamente alle specifiche (come definito dal punto precedente).
  • Mostrano come l'unità / classe / modulo / funzione / metodo non funziona in presenza di input imprevisti.
  • Forniscono esempi su come utilizzare l'unità, che è un'ottima documentazione per i nuovi membri del team.
risposta data 10.10.2010 - 14:43
fonte
8

Se intendi il privato nel modo in cui penso tu intenda, allora no - non dovresti essere un'unità di testarlo. Dovresti essere solo unità test di comportamento osservabile / stato. Potrebbe mancare il punto dietro il ciclo "red-green-refactor" di TDD (e se non stai facendo il test prima, si applica lo stesso principio). Una volta che i test sono stati scritti e passati, non vuoi che cambino durante l'esecuzione del refactoring. Se sei costretto a testare l'unità funzionalità privata allora probabilmente significa che i test unitari intorno alla funzionalità pubblica sono difettosi. Se è difficile e complesso scrivere test attorno al codice pubblico, forse la tua classe sta facendo troppo o il tuo problema non è chiaramente definito.

Peggio ancora, col passare del tempo i tuoi test unitari diventeranno una palla al piede che ti rallenta senza aggiungere alcun valore (cambiare l'implementazione, ad esempio l'ottimizzazione o la rimozione della duplicazione, non dovrebbe avere alcun effetto sui test delle unità). Il codice interno dovrebbe, tuttavia, essere testato unitamente in quanto il comportamento / stato è osservabile (solo in modo limitato).

Quando ho effettuato per la prima volta i test unitari ho tirato ogni sorta di trucchetti per le prove private unitarie, ma ora, con qualche anno di vita, vedo che è peggio di una perdita di tempo.

Ecco un esempio un po 'sciocco, ovviamente nella vita reale ci sarebbero più test di questi:

Supponiamo che tu abbia una classe che restituisce una lista ordinata di stringhe: dovresti controllare che il risultato sia ordinato, non come lo elenchi effettivamente. Potresti iniziare la tua implementazione con un singolo algoritmo che ordina solo la lista. Una volta fatto, il test non deve essere modificato se si modifica l'algoritmo di ordinamento. A questo punto hai un solo test (supponendo che l'ordinamento sia incorporato nella tua classe):

  1. Il mio risultato è ordinato?

Ora dì che vuoi due algoritmi (forse uno è più efficiente in alcune circostanze ma non in altri), quindi ogni algoritmo potrebbe (e generalmente dovrebbe) essere fornito da una classe diversa e le scelte di classe da loro - puoi controllare questo sta accadendo per i tuoi scenari scelti usando i mock, ma il tuo test originale è ancora valido e poiché stiamo verificando solo il comportamento osservabile / stato non ha bisogno di cambiare. Finisci con 3 test:

  1. Il mio risultato è ordinato?
  2. Dato uno scenario (diciamo che l'elenco iniziale è quasi ordinato per iniziare) è una chiamata fatta alla classe che ordina le stringhe usando l'algoritmo X?
  3. Dato uno scenario (la lista iniziale è in ordine casuale) è una chiamata alla classe che ordina le stringhe usando l'algoritmo Y?

L'alternativa sarebbe stata iniziare a testare il codice privato all'interno della tua classe - non ottieni nulla da questo - i test sopra riportati mi dicono tutto quello che devo sapere per quanto riguarda il test unitario. Aggiungendo test privati ti stai costruendo una giacca diritta, quanto più lavoro sarebbe se non solo verificassi che il risultato fosse ordinato ma anche come è ordinato?

I test (di questo tipo) dovrebbero cambiare solo quando il comportamento cambia, iniziare a scrivere test sul codice privato e quello esce dalla finestra.

    
risposta data 10.10.2010 - 21:10
fonte
4

ecco un altro motivo: nel caso ipotetico dovrei scegliere tra unità testare l'API esterna rispetto alle parti private, sceglierei le parti private.

Se ogni parte privata è coperta da un test, l'API composta da queste parti private dovrebbe essere coperta anche per quasi il 100%, eccetto per il livello superiore. Ma è probabile che sia un sottile strato.

D'altra parte, quando si testano solo le API, può essere davvero difficile coprire completamente tutti i possibili percorsi di codice.

    
risposta data 10.10.2010 - 15:41
fonte
2

È difficile convincere le persone ad accettare i test unitari perché sembra uno spreco di tempo ("potremmo codificare un altro progetto redditizio!") o ricorsivo ("E poi dobbiamo scrivere casi di test per i casi di test ! ") Sono colpevole di averlo detto entrambi.

La prima volta che trovi un bug, devi affrontare la verità che non sei perfetto (quanto velocemente noi programmatori dimentichiamo!) e tu vai, "Hmmm."

Un altro aspetto dei test unitari è che il codice deve essere scritto per essere testabile. Rendendosi conto che alcuni codici sono facilmente testabili e alcuni codici non rendono un buon programmatore "Hmmm".

Hai chiesto al tuo collaboratore perché il test dell'unità è stato utile solo per le API rivolte all'esterno?

Un modo per mostrare il valore del test delle unità è aspettare che si verifichi un brutto bug e quindi mostrare come il test dell'unità potrebbe averlo impedito. Quello non è quello di strusciarglielo in faccia, cioè, nelle loro menti, spostare i test unitari da una Torre d'Avorio teorica a una realtà in trincea.

Un altro modo è aspettare che si verifichi lo stesso errore due volte . "Uhhh, bene Boss, abbiamo aggiunto il codice per testare il nulla dopo il problema della settimana scorsa, ma questa volta l'utente ha inserito una cosa vuota!"

Guida con l'esempio. Scrivi test unitari per il TUO codice, quindi mostra al tuo capo il valore. Poi vedi se il capo chiamerà la pizza per pranzo un giorno e farà una presentazione.

Infine, non posso dirti il sollievo che provo quando stiamo per spingere ai pungoli e ottengo una barra verde dai test delle unità.

    
risposta data 10.10.2010 - 16:50
fonte
2

Esistono due tipi di codice privato: codice privato che viene chiamato da codice pubblico (o codice privato che viene chiamato da un codice privato che viene chiamato da codice pubblico (o ...)) e codice privato che fa non verrà chiamato per codice pubblico.

Il primo viene già testato attraverso i test per il codice pubblico. Quest'ultimo non può essere chiamato affatto e quindi dovrebbe essere cancellato, non testato.

Si noti che quando si esegue TDD è impossibile che esista un codice privato non verificato.

    
risposta data 11.10.2010 - 04:26
fonte
2

Il test delle unità riguarda esclusivamente le unità di test del codice. Spetta a te definire cos'è un'unità. I tuoi colleghi definiscono le unità come elementi API.

In ogni caso, l'API di test dovrebbe comportare l'esercizio di codice privato. Se si definisce la copertura del codice come un indicatore del progresso del test delle unità, si finirà per testare tutto il codice. Se una parte del codice non è stata raggiunta, dai ai tuoi colleghi tre scelte:

  • definisce un altro test case per coprire quella parte,
  • analizza il codice per giustificare il motivo per cui non può essere coperto nel contesto del test unitario ma deve essere coperto in altre situazioni,
  • rimuovi il codice morto che non è stato coperto non è giustificato.
risposta data 12.10.2010 - 10:54
fonte

Leggi altre domande sui tag