La copertura di prova è una misura adeguata della qualità del codice?

19

Se ho un codice che ha una copertura di prova dell'80% (tutti i test superano), è giusto dire che è di qualità superiore rispetto al codice senza copertura del test?

O è giusto dire che è più gestibile?

    
posta David_001 01.09.2010 - 23:24
fonte

7 risposte

24

In senso stretto, non è giusto fare affermazioni fino a quando non viene stabilita la qualità della suite di test. Passare il 100% dei test non è significativo se la maggior parte dei test è banale o ripetitiva l'uno con l'altro.

La domanda è: Nella storia del progetto, qualcuno di questi test ha scoperto bug? L'obiettivo di un test è trovare i bug. E se non lo facessero, fallirono come test. Invece di migliorare la qualità del codice, potrebbero darti solo un falso senso di sicurezza.

Per migliorare i tuoi progetti di test, puoi utilizzare (1) tecniche whitebox, (2) tecniche blackbox e (3) test di mutazione.

(1) Ecco alcune buone tecniche whitebox da applicare ai progetti di test. Un test whitebox è costruito tenendo conto del codice sorgente specifico. Un aspetto importante del test di whitebox è la copertura del codice:

  • Viene chiamata ogni funzione? [Copertura funzionale]
  • Viene eseguita ogni istruzione? [Copertura informativa: sia la copertura funzionale che la copertura delle dichiarazioni sono molto semplici, ma meglio di niente]
  • Per ogni decisione (come if o while ), hai un test che lo costringe a essere vero, e un altro che lo costringe a essere falso? [Copertura decisionale]
  • Per ogni condizione che è una congiunzione (usa && ) o disgiunzione (usa || ), ciascuna sottoespressione ha un test in cui è vero / falso? [Copertura delle condizioni]
  • Copertura del ciclo: hai un test che forza 0 iterazioni, 1 iterazione, 2 iterazioni?
  • Ogni break è coperto da un loop?

(2) Le tecniche Blackbox vengono utilizzate quando i requisiti sono disponibili, ma il codice stesso non lo è. Questi possono portare a test di alta qualità:

  • I tuoi test blackbox coprono più obiettivi di test? Avrai bisogno che i tuoi test siano "grassi": non solo testano la funzione X, ma testano anche Y e Z. L'interazione di diverse funzionalità è un ottimo modo per trovare bug.
  • L'unico caso in cui non desideri test "grassi" è quando stai testando una condizione di errore. Ad esempio, test per input utente non valido. Se hai provato a raggiungere più obiettivi di test dell'input non validi (ad esempio, un codice postale non valido e un indirizzo non valido) è probabile che un caso stia mascherando l'altro.
  • Considera i tipi di input e forma una "classe di equivalenza" per i tipi di input. Ad esempio, se il tuo codice verifica se un triangolo è equilatero, il test che usa un triangolo con lati (1, 1, 1) troverà probabilmente gli stessi tipi di errori dei dati del test (2, 2, 2) e (3, 3, 3) troveranno. È meglio passare il tempo a pensare ad altre classi di input. Ad esempio, se il tuo programma gestisce le tasse, ti consigliamo di effettuare un test per ogni fascia fiscale. [Questo è chiamato partizionamento dell'equivalenza.]
  • I casi speciali sono spesso associati a difetti. I dati del test devono anche avere valori limite, come quelli sopra, sopra o sotto i bordi di un compito di equivalenza. Ad esempio, nel testare un algoritmo di ordinamento, ti consigliamo di testare con un array vuoto, un singolo array di elementi, un array con due elementi e quindi un array molto grande. Dovresti considerare i casi limite non solo per l'input, ma anche per l'output. [Questa è l'analisi del valore limite di chiamata.]
  • Un'altra tecnica è "Errore nell'indovinare". Hai la sensazione se provi qualche combinazione speciale per far si che il tuo programma si rompa? Quindi provalo! Ricorda: il tuo obiettivo è trovare i bug, non confermare che il programma sia valido . Alcune persone hanno l'abilità di indovinare l'errore.

(3) Infine, supponiamo che tu abbia già molti buoni test per la copertura di whitebox e tecniche di blackbox applicate. Cos'altro puoi fare? È tempo di Testare le tue prove . Una tecnica che puoi usare è Test di mutazione.

Sotto test di mutazione, fai una modifica a (una copia del) tuo programma, nella speranza di creare un bug. Una mutazione potrebbe essere:

Change a reference of one variable to another variable; Insert the abs() function; Change less-than to greater-than; Delete a statement; Replace a variable with a constant; Delete an overriding method; Delete a reference to a super method; Change argument order

Crea diverse decine di mutanti, in vari punti del tuo programma [il programma dovrà comunque essere compilato per testare]. Se i tuoi test non trovano questi bug, ora devi scrivere un test che trovi il bug nella versione mutata del tuo programma. Una volta che un test trova il bug, hai ucciso il mutante e puoi provarne un altro.

Addendum : ho dimenticato di menzionare questo effetto: I bug tendono a raggruppare . Ciò significa che più bug si trovano in un modulo, maggiore è la probabilità che troverai più bug. Quindi, se hai un test che fallisce (il che significa che il test ha esito positivo, dato che l'obiettivo è trovare i bug), non solo dovresti correggere il bug, ma dovresti anche scrivere più test per il modulo, usando il tecniche sopra.

Finché si trovano bug a velocità costante, gli sforzi di test devono continuare. Solo quando si riscontra un calo nel tasso di nuovi bug riscontrati dovresti avere la certezza di aver compiuto buoni sforzi di test per quella fase di sviluppo.

    
risposta data 26.10.2010 - 07:03
fonte
7

In base a una definizione, è più gestibile, poiché è più probabile che qualsiasi errore di rottura venga rilevato dai test.

Tuttavia, il fatto che il codice superi i test unitari non significa che sia intrinsecamente di qualità superiore. Il codice potrebbe ancora essere formattato male con commenti irrilevanti e strutture di dati inappropriate, ma può comunque superare i test.

So quale codice preferirei mantenere ed estendere.

    
risposta data 01.09.2010 - 23:27
fonte
7

Il codice con nessun test può essere estremamente di alta qualità, leggibile, bello ed efficiente (o totale spazzatura), quindi no, non è giusto dire che il codice con copertura di prova dell'80% è di qualità superiore rispetto al codice senza copertura di test .

Potrebbe essere corretto dire che il codice 80% coperto con test buoni è probabilmente di qualità accettabile, e probabilmente relativamente mantenibile. Ma garantisce poco, davvero.

    
risposta data 26.10.2010 - 07:56
fonte
3

Lo chiamerei più rifattorico. Il refactoring diventa estremamente facile se il codice è coperto da molti test.

Sarebbe corretto definirlo più gestibile.

    
risposta data 01.09.2010 - 23:26
fonte
2

Sarei d'accordo sulla parte gestibile. Michael Feathers ha recentemente pubblicato un video di un eccellente discorso sul suo " La profonda sinergia tra testabilità e buon design " in cui discute questo argomento. Nel discorso dice che la relazione è unidirezionale, cioè il codice che è ben progettato è testabile, ma il codice testabile non è necessariamente ben progettato.

Vale la pena notare che lo streaming video non è eccezionale nel video, quindi potrebbe valerne la pena scaricarlo se si desidera guardarlo per intero.

    
risposta data 02.09.2010 - 00:30
fonte
-2

Mi sono posto questa domanda da un po 'di tempo in relazione alla "copertura delle condizioni". Che ne dici di questa pagina di atollic.com "Perché l'analisi della copertura del codice?"

More technically, code coverage analysis finds areas in your program that is not covered by your test cases, enabling you to create additional tests that cover otherwise untested parts of your program. It is thus important to understand that code coverage helps you understand the quality of your test procedures, not the quality of the code itself.

Questo sembra essere abbastanza rilevante qui. Se si dispone di un set di test case che riesce a raggiungere un certo livello di copertura (di codice o di altro tipo), è molto probabile che si invochi il codice sotto test con un insieme piuttosto esauriente di valori di input! Questo non ti dirà molto del codice sotto test (a meno che il codice non esploda o generi errori rilevabili) ma ti dia sicurezza nel set di casi di test .

In un interessante Necker Cube cambio di vista, il codice di prova viene ora testato dal codice sotto test !

    
risposta data 23.04.2014 - 19:20
fonte
-3

Ci sono molti modi per garantire che un programma faccia ciò che si intende e per garantire che le modifiche non abbiano effetti indesiderati.

Il test è uno. Evitare la mutazione dei dati è un altro. Quindi è un sistema di tipo. O verifica formale.

Quindi, mentre sono d'accordo sul fatto che il test sia generalmente una buona cosa, una data percentuale di test potrebbe non significare molto. Preferisco fare affidamento su qualcosa scritto in Haskell senza test che su una libreria PHP ben collaudata

    
risposta data 23.04.2014 - 19:36
fonte

Leggi altre domande sui tag