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?
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:
if
o while
), hai un test che lo costringe a essere vero, e un altro che lo costringe a essere falso? [Copertura decisionale] &&
) o disgiunzione (usa ||
), ciascuna sottoespressione ha un test in cui è vero / falso? [Copertura delle condizioni] 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à:
(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.
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.
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.
Lo chiamerei più rifattorico. Il refactoring diventa estremamente facile se il codice è coperto da molti test.
Sarebbe corretto definirlo più gestibile.
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.
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 !
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
Leggi altre domande sui tag code-quality test-coverage