È tipico che una suite di test di unità sia più grande del codice che prova? [duplicare]

9

Ho riscontrato che il più delle volte, quando si scrivono molti test unitari e si ha una buona copertura (80% circa), la suite di test finisce per essere più grande del codice stesso.

Le mie osservazioni corrispondono a quelle di tutti gli altri?

Ho anche riscontrato che più spesso, più grande è la suite di test, più difficile è mantenere la suite di test. Quello che finisce per accadere è che la suite di test si decompone come per ogni X riga che si modifica apportata al codice, X ^ 2 linee devono cambiare nella suite di test.

Questo è un attributo delle unit test suite in generale? O sto solo lavorando su suite di test di unità scadenti?

    
posta nbv4 22.08.2012 - 05:37
fonte

5 risposte

7

Test più grandi del codice?

Dipende.

A volte il test sarà più complesso.

A volte il codice sarà più complesso.

Rifattorizzazione per semplificare codice e casi di test

Potrebbe valere la pena prendere in considerazione alcune semplificazioni e refactoring se le cose stanno diventando esponenziali per te.

Ho lavorato con diversi progetti di manutenzione che sono stati disseminati di lezioni di Dio. Questi tendevano ad essere molto più gestibili quando refactored in classi più piccole.

Alcune classi non sono minime e una ricerca di codice ripetuto, e il refactoring per eliminare la ripetizione ha il potenziale per ridurre significativamente la superficie del test.

Black Box vs. Glass Box Testing

Un problema che si pone è quello della metodologia TDD. Quando la storia dell'utente cambia, questo produce più test. All'esecuzione iniziale, falliscono e viene scritto più codice per farli passare. Quando passano, la user story è implementata e spediamo. Naturalmente, nella vita reale, le cose potrebbero non essere così pure. Tuttavia, credo che valga la pena chiedere quanto la storia utente elabora i casi di test? I test case sono funzionali, test della scatola nera basato sull'esercizio degli input validi e non validi?

Dalla tua descrizione sembra che alcuni dei casi di test siano finalizzati alla copertura delle dichiarazioni. Mi piace la copertura informativa, ma ci sono anche molti altri tipi di copertura. Ci sono metodi per ottimizzare i casi di test di copertura che dovresti prendere in considerazione se trovi che parte del tuo alto numero di casi di test è dovuta alla forza bruta che costringe le cose a passare attraverso ogni linea.

Tipi di copertura del codice

Il seguente link illustra con una bella grafica diversi tipi di copertura. Non sostengo o non ho un'opinione sul loro prodotto, solo sul loro diagramma.

link

Nel loro esempio mostrano la condizione / copertura delle decisioni modificate e stabiliscono che per il codice che mostrano, quattro test case eseguono entrambe le istruzioni e causano la ramificazione nell'istruzione if per ogni tipo di condizione che potrebbe verificarsi. Scoperta di casi di test quando i criteri decisionali sono confronti annidati come

if (a < 5) // d1
   if (b < 10) //d2
      a = 7;

if ((a + b) < 8) //d3
   c = 5;

può essere più difficile da analizzare per i valori del test case, ma sai che avrai bisogno di un test case con un < 5 e a > = 5 dal primo se, e anche b < 10 e b > = b dal secondo if.

Perché in alcuni percorsi a sarà l'input, e altri a sarà un valore modificato (a = 7), potresti aver bisogno di usare una tecnica chiamata esecuzione simbolica dove la terza se viene analizzata in termini di a 'e a ''. Per eseguire c = 5, è necessario un caso di test in cui la condizione è soddisfatta. Dovrai anche eseguire un test in cui c non viene mai assegnato.

Un elenco di casi di test che penso riguardi tutto:

T1: a=4, b=9 => a'=4, a''=7, covers d1=true, d2=true, d3=false
T2: a=5, b=9, covers d1=false
T3: a=4, b=10, covers d2= true

Ma come viene coperto d3? Assegnare a in se la seconda istruzione rende l'analisi più complicata a meno che non facciamo questo con esso.

((a' + b) < 8), ((a'' + b) < 8)

((a' + b) < 8), ((7 + b) < 8)  // Remember a'' = 7

((a' + b) < 8), (b < 1)  // Remember a'' = 7 

T4: a = 1, b = 0, copre d3 = true

L'esecuzione simbolica è una tecnica correlata al test che è possibile utilizzare per ridurre i casi di test necessari per eseguire la copertura decisionale. Non è una lettura facile, ma una carta classica sull'argomento è:

link

Ci scusiamo se questo si allontana troppo dalla tua domanda originale. Spero che sarà di qualche utilità.

    
risposta data 22.08.2012 - 08:23
fonte
4

Questo può davvero accadere quando si scrivono molti test unitari e si fa un sacco di TDD. Quando arrivi a un punto in cui la suite di test ti impedisce di apportare modifiche a una funzione specifica nel tuo codice, la tua suite di test probabilmente contiene troppe chiamate (simili all'aspetto) a questa stessa funzione del codice. Questo è quasi sempre un segnale per la tua suite di test che non è più "ASCIUTTA". I miei suggerimenti per evitare che:

  • ridefinisci regolarmente la tua suite di test per renderla più ASCIUTTA . Raggruppare le chiamate di funzione al codice se sembrano simili in una funzione centrale, raggruppare la creazione dei dati di test se i dati di test vengono riutilizzati per più di un test, scrivere funzioni di supporto per consentire il confronto di oggetti complessi con i valori previsti in meno linee di codice e così via.
  • scrivi test parametrizzati e guidati dai dati . La maggior parte dei moderni framework di test unitari consentono di scrivere una funzione di test una volta e di fornire diversi set di dati di test. Se il tuo framework non ha il supporto diretto per questa tecnica, puoi facilmente crearlo manualmente.

Potrebbe anche essere una buona idea studiare una teoria dei test "classica" (vedi, per esempio, qui ) come progettare sistematicamente il minor numero di casi di test possibile per ottenere una copertura elevata.

    
risposta data 22.08.2012 - 08:07
fonte
1

Ho lavorato in un progetto Java in cui avevamo una copertura del codice superiore al 90%. Il codice dei test unitari era decisamente superiore al codice del progetto (direi circa il 20% in più).

D'altra parte abbiamo avuto pochissimi bug.

    
risposta data 22.08.2012 - 10:39
fonte
1

the test suite ends up being larger than the code itself.

Do my observations match that of everyone else?

  • Se si intende che la suite di test nel suo complesso ha più LoC di tutto il codice dell'applicazione, quindi no, non l'ho mai provato. Forse perché ho lavorato a progetti con molti test unitari, non molti test di integrazione e zero test UI automatizzati. L'interfaccia utente può essere davvero enorme in termini di linee di codice, quindi suppongo che sia necessario avere test dell'interfaccia utente completi affinché la dimensione della base del codice di test superi la dimensione totale della base del codice di produzione.

  • Se vuoi dire che il tuo dispositivo di prova medio ha più LoC del modulo che prova, è possibile, specialmente se il tuo codice di produzione ha molti metodi pubblici e brevi. Tuttavia, potrebbe anche significare che stai testando troppe cose. Cose come accessors e costrutti di codice che non contengono alcuna logica sono generalmente considerati non degni di essere testati.

the larger the test suite, the harder it is to maintain the test suite.

Suppongo che non ci sia molto da fare per quel fatto matematico. Non puoi aspettarti che la tua suite di test arrivi senza alcun costo e il costo aumenterà naturalmente con le sue dimensioni. Ci sono cose che puoi fare per test troppo fragili. Vedi link .

    
risposta data 22.08.2012 - 17:32
fonte
0

Avere più codice nel test per una determinata funzione è un segno che la funzione / metodo non si attiene al singolo principio di responsabilità.

Questo significa che con il tempo il codice diventa più complicato e che i test devono crescere di dimensioni in modo esponenziale per adattarsi a tutti i percorsi del codice e alle possibili combinazioni di parametri.

La maggior parte degli anti-pattern là fuori viola il principio di responsabilità singola, quindi è la prima cosa che esce dalla finestra in un tipico progetto. Questo porta alla situazione che hai citato.

Una soluzione a questo è scrivere test concisi per una determinata routine prima di scrivere la routine . Se i test sono troppo complicati significa che è ora di refactoring .

    
risposta data 22.08.2012 - 10:26
fonte

Leggi altre domande sui tag