Qual è il modo migliore per organizzare i nostri test unitari


18

Nel corso degli anni abbiamo realizzato un numero considerevole di test unitari per il nostro programma principale. Molte migliaia. Il problema è che non abbiamo un'idea chiara di quali test abbiamo perché ce ne sono così tanti. E questo è un problema perché non sappiamo dove siamo deboli nei test (o dove abbiamo duplicati).

La nostra app è un motore di reportistica. Quindi puoi avere un modello che viene utilizzato per testare l'analisi (leggiamo tutte le proprietà della tabella), unendo i dati (abbiamo mantenuto le proprietà della tabella corrette nell'unione), formattando la pagina finale (la tabella è posizionata correttamente sulla pagina ) e / o il formato di output (il file DOCX creato è corretto).

Aggiungi a questo ciò che dobbiamo testare. Prendi il padding attorno a una cella di tabella (usiamo Word, Excel e PowerPoint per la progettazione del report). Dobbiamo testare il riempimento attraverso l'interruzione di pagina, per una tabella all'interno di una cella, celle unite verticalmente, celle unite orizzontalmente, una cella unita verticalmente e orizzontalmente che contiene una tabella con celle unite verticalmente e orizzontalmente nella tabella interna, dove quella tabella si rompe su una pagina.

Quindi in quale categoria rientra quel test? Riempimento tabella, interruzioni di pagina, celle nidificate, celle unite verticalmente, celle unite orizzontalmente o qualcos'altro?

E come documentiamo queste categorie, nominiamo i test unitari, ecc.?

Aggiornamento: alcune persone hanno suggerito di utilizzare gli strumenti di copertura per verificare che la copertura sia completa. Sfortunatamente questo è di utilità limitata nel nostro caso perché i bug tendono ad essere dovuti a combinazioni specifiche, quindi è il codice che è stato tutto testato, ma non in quella combinazione.

Ad esempio, ieri abbiamo avuto un cliente che ha avviato un segnalibro di Word alla fine di un ciclo forEach nel suo modello (un documento di Word) e lo ha terminato all'inizio del ciclo successivo per Ogni ciclo. Tutto questo ha usato un codice che ha dei test unitari, ma non avevamo pensato alla combinazione di un modello che espandeva un segnalibro che iniziava per essere avviato 25 volte, per poi terminare 10 volte (i due cicli per ogni ciclo avevano un numero diverso di righe).


1
Sembra che la tua domanda sia davvero: come facciamo a sapere se abbiamo testato uno scenario particolare?
Andy Wiesendanger,

Sì! E anche dove sono i test per eventuali scenari simili. E da ciò otteniamo il bisogno n. 2: leggere ciò che è coperto ci aiuta a trovare ciò che ci siamo persi.
David Thielen,

Risposte:


13

In genere, tendo a rispecchiare l'albero dei sorgenti per i miei test unitari. Quindi, se avessi src / lib / fubar, avrei un test / lib / fubar che conterrebbe i test unitari per fubar.

Tuttavia, ciò che sembra descrivere sono altri test funzionali. In tal caso, avrei una tabella multidimensionale che elenca tutte le tue possibili condizioni. Quindi, quelli che non hanno test sono privi di senso o necessitano di un nuovo test. Ovviamente puoi metterli in serie di test suite.


Attualmente rispecchiamo l'albero dei sorgenti. Ma abbiamo due problemi. Innanzitutto, per la formattazione della tabella, ci sono oltre 100 test diversi. Tenere traccia di ciò che è esattamente testato è diventato un problema. In secondo luogo, aree funzionali molto diverse devono testare le tabelle: i parser, la sostituzione dei dati, la formattazione e la creazione del documento di output. Quindi penso che tu abbia ragione, in un certo senso si tratta di test funzionali di una determinata proprietà.
David Thielen,

Il che porta alla domanda: dove conserviamo la tabella dei test? Sto pensando a un foglio di calcolo nella directory dei sorgenti di root ???
David Thielen,

Lo memorizzerei in un foglio di calcolo controllato nella directory di test. Se hai molte cose che devi testare, scomporle in meta-strutture sarebbe utile. Prova a pensare in termini di cosa generale viene testata invece di cosa o come.
Sardathrion - Ripristina Monica il

7

La struttura più comune sembra essere il mirror della directory srce test.

src/module/class
test/module/class_test

Tuttavia, ho visto una struttura alternativa che ora ritengo migliore.

src/module/class
src/module/class_test

Poiché unit test tende a rispecchiare la classe che stanno testando, posizionandoli nella stessa directory si ottiene un accesso molto più semplice ai file in modo da poter lavorare fianco a fianco.


2
Uno svantaggio del precedente approccio è che ogni volta che decidi di modificare la struttura dei file del progetto, devi fare lo stesso per la struttura dei test. Questo problema non esiste se i test sono dove si trova il codice.
victor175,

5

In .NET, tendo a rispecchiare, o almeno approssimare, la struttura dello spazio dei nomi per il codice sorgente nei progetti di test, sotto uno spazio dei nomi principale "Tests.Unit" o "Tests.Integration". Tutti i test unitari vanno in un progetto, con la struttura di base del codice sorgente replicata come cartelle all'interno del progetto. Lo stesso vale per i test di integrazione. Quindi, una soluzione semplice per un progetto potrebbe apparire così:

Solution
   MyProduct.Project1 (Project)
      Folder1 (Folder)
         ClassAA (Class def)
         ...
      Folder2
         ClassAB
         ...
      ClassAC
      ...
   MyProduct.Project2
      Folder1
         ClassBA
         ...
      ClassBB
      ...
   ...
   MyProduct.Tests.Unit
      Project1
         Folder1
            ClassAATests
            ClassAATests2 (possibly a different fixture setup)
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests
      ...
   MyProduct.Tests.Integration
      Project1 (a folder named similarly to the project)
         Folder1 (replicate the folders/namespaces for that project beneath)
            ClassAATests
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests

Per eventuali AAT o AEET codificati con un framework di unit test, questo cambia un po '; di solito questi test rispecchiano una serie di passaggi, che metteranno alla prova la funzionalità di un nuovo caso d'uso o storia. Di solito strutturo questi test in un MyProduct.Tests.Acceptanceprogetto come tale, con test per ogni storia, possibilmente raggruppati per traguardo o storia "epica" a cui apparteneva la storia in fase di sviluppo. Tuttavia, questi sono davvero solo test di super integrazione, e quindi se preferisci strutturare i test in modo più orientato agli oggetti invece che alla storia, non hai nemmeno bisogno di un MyProduct.Tests.Acceptanceprogetto o simile; basta lanciarli MyProduct.Tests.Integrationsotto l'ambito dell'oggetto di massimo livello sotto test.


3

Non vi è alcun motivo per cui un test unitario rientri in una sola categoria. Tutti i principali toolkit di unit test supportano la creazione di suite di test , che raggruppano i test per una particolare categoria. Quando una particolare area di codice è stata modificata, lo sviluppatore dovrebbe eseguire prima quella suite e spesso per vedere cosa si è rotto. Quando un test di preoccupazioni imbottitura e le pause e la nidificazione, con tutti i mezzi messi in tutte e tre le suite.

Detto questo, il punto dei test unitari è quello di eseguirli sempre, ovvero dovrebbero essere abbastanza piccoli e veloci da poter essere eseguiti tutti prima di commettere qualsiasi codice. In altre parole, non importa quale categoria sia un test, dovrebbe comunque essere eseguito prima di eseguire il commit. Le suite sono davvero solo una stampella che usi se per qualche motivo non riesci a scrivere test veloci come dovrebbero.

Per quanto riguarda la copertura, ci sono ottimi strumenti di copertura che ti dicono quale percentuale di linee è stata effettivamente esercitata eseguendo i tuoi test - questo è un ovvio indicatore del tipo di test che ti mancano ancora.

Per quanto riguarda la denominazione, non vi è alcun valore particolare nell'impegno profuso sui nomi dei test unitari. Tutto quello che vuoi sentire dai tuoi test è "5235 di 5235 test superati". Quando un test fallisce, quello che leggi non è il suo nome, ma il messaggio , ad es. La stringa assert()che implementa il tuo criterio di successo. Il messaggio dovrebbe essere abbastanza informativo da avere un'idea di cosa non va senza leggere il corpo del test. Il nome non è importante rispetto a quello.


Accetta il 100% su tutto ciò che dici (la nostra macchina per la costruzione esegue tutti i test al momento del check-in). Il nostro grosso problema è tenere traccia di ciò che stiamo testando. E la copertura del codice non è di grande aiuto (vedi aggiornamento sopra).
David Thielen,

1

Un modo per sapere se sei debole nei test è la tracciabilità. Di solito per i test, questo assume la forma di copertura.

L'obiettivo è misurare quali parti del codice vengono esercitate dai test, in modo da poter vedere il codice che non è coperto dai test. Spetta a te (e allo strumento di copertura) definire cos'è una "parte di codice". Il minimo è la copertura delle filiali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.