Tutti i test unitari in un eseguibile o suddivisi?


12

Quando scrivi test per un software, ad esempio una libreria, preferisci compilare tutti i test unitari in uno o separarli in più eseguibili?

Il motivo per cui lo sto chiedendo è perché attualmente sto usando CUnit per testare una libreria su cui sto lavorando. I test sono suddivisi in suite separate che vengono compilate in un eseguibile completo di output stampato per errori. Ora, il sistema di compilazione per quella libreria è CMake (che, nonostante il suo nome, ha poco a che fare con CUnit), che viene fornito con il suo framework di test, CTest . CTest mi consente di registrare un elenco di file eseguibili che fungono da test.

Sto meditando se usare CTest per le prove automatizzate. Tuttavia, questo richiederebbe di dividere i test che ho scritto finora in target di compilazione separati. Altrimenti, non posso davvero utilizzare alcune delle funzionalità avanzate di CTest, come l'esecuzione selettiva dei test.

Mi rendo conto che si tratta più di una questione di quali strumenti utilizzare e della loro gestione e convenzioni, ma a parte questo, ci sono altri motivi per preferire un singolo test eseguibile rispetto a quelli separati? O vice versa?


Separarli in eseguibili separati per classe. Ogni classe dovrebbe avere il proprio test unitario a meno che la classe non sia unitamente testabile e quindi debba essere testata indirettamente da altre classi.
Brian

1
Se disponi di una libreria di grandi dimensioni con centinaia di classi, ciascuna con un test unitario, il tempo di compilazione è molto più lungo se crei un binario completo per ciascuno, rispetto a uno (o pochi) binari di grandi dimensioni. Inoltre, ci sono molti makefile da gestire, ognuno con singole linee di collegamento.
JBR Wilkinson,

Non è così grande. Meno di 20 moduli. Sono anche in grado di compilarli tutti con gli stessi flag, quindi CMake può generare i Makefile senza molto lavoro da parte mia.
Benjamin Kloster,

Risposte:


5

Mi piace avere i miei test automatici in singoli binari, o almeno raggruppati per gruppo "appartiene-insieme", e quindi chiamarli da un semplice script di shell (in cui un codice di uscita diverso da zero segnala un errore e l'output su stderr può essere acquisito per registrare una spiegazione). In questo modo, mantengo la massima flessibilità nei test: posso eseguire singoli test direttamente dalla riga di comando, posso creare tutti i tipi di script di fantasia se voglio, posso riordinarli come ritengo opportuno senza ricompilare nulla, ecc.

Ma soprattutto, mi permette anche di includere test scritti in lingue diverse o usando diverse toolchain nella stessa corsa. Ad esempio, i test unitari che scrivo sono molto probabilmente nella lingua principale del progetto, ed eseguirli è una questione di costruzione e invocazione dei file binari; ma voglio anche testare il mio database e potrei voler alimentare gli script SQL direttamente nel database per questo; Potrei voler eseguire uno strumento di analisi del codice statico sul mio codice (anche se è solo una sorta di linter). Potrei voler eseguire il mio HTML statico attraverso un controllo di validità. Potrei eseguire un grepcomando sopra la base di codice per verificare la presenza di costrutti sospetti, violazioni dello stile di codifica o parole chiave "bandiera rossa". Le possibilità sono infinite: se può essere eseguito dalla riga di comando e aderisce allo "stato di uscita zero significa OK", posso usarlo.


L'argomento agnostico del linguaggio è un ottimo punto, dal momento che ho intenzione di implementare i collegamenti Python per la libreria lungo la strada. Grazie!
Benjamin Kloster,

@tdammers: qualche particolare framework di test?
JBR Wilkinson,

@JBRWilkinson: solo uno script di shell a 30 righe. Per la maggior parte delle lingue che uso, ho piccole librerie in giro per attività di test comuni come l'esecuzione di una funzione, il confronto del risultato con un valore previsto e il lancio quando non corrispondono. Ma qualsiasi dato framework di unit test potrebbe facilmente essere integrato in un tale "meta-sistema", purché possa essere eseguito dalla riga di comando e segnali di successo / fallimento attraverso il suo stato di uscita.
tdammers,

2

Tendo ad avere una libreria per i test unitari di un'applicazione (o per un pacchetto di librerie comunemente condiviso). All'interno di quella libreria, provo a replicare o approssimare gli spazi dei nomi degli oggetti testati per i dispositivi di test (uso principalmente NUnit). Ciò semplifica la compilazione, poiché in .NET esiste un sovraccarico inerente alla creazione di ogni binario che aumenterebbe il tempo di compilazione di una soluzione a 20 progetti rispetto a quello di una soluzione a 10 progetti con lo stesso LOC. I file binari di test non sono comunque distribuiti, quindi qualsiasi organizzazione dei test in file binari è per tua comodità, e generalmente trovo che YAGNI si applichi qui come ovunque.

Ora, di solito non ho le considerazioni che tdammers ha; il mio codice è praticamente tutto in una lingua, e qualsiasi test che coinvolge stringhe SQL non è un test unitario (a meno che tu non stia testando che un produttore di query restituisce la stringa SQL prevista dati determinati criteri), e praticamente non testo mai l'unità UI (in molte situazioni è semplicemente impossibile). Uso anche una libreria di test di unità che è ben accettata da strumenti di terze parti come build-bot e plugin IDE, e quindi qualsiasi preoccupazione relativa all'esecuzione di test individuali, suite parziali ecc. È minima.


1
Una questione di cultura, immagino - in un ambiente .NET, probabilmente ragionerei molto come te.
tdammers,
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.