I test dell'unità possono verificare i requisiti software?

2

Ho spesso sentito test unitari per aiutare i programmatori a creare fiducia nel loro software. Ma è sufficiente per verificare che i requisiti software siano soddisfatti? Sto perdendo la fiducia che il software funzioni solo perché i test delle unità passano.

Abbiamo riscontrato alcuni errori nella distribuzione della produzione a causa di un percorso di esecuzione \ non verificato non verificato. Questi errori sono a volte piuttosto grandi, influenzano le operazioni aziendali e spesso richiedono una correzione immediata.

L'errore viene raramente ricondotto a un test dell'unità in errore. Abbiamo corpi di test unitari di grandi dimensioni con una copertura della linea ragionevole, ma quasi tutti si concentrano su singole classi e non sulle loro interazioni.

I test manuali sembrano inefficaci perché il software su cui si sta lavorando è in genere di grandi dimensioni con molti percorsi di esecuzione e molti punti di integrazione con altri software. È molto doloroso testare manualmente tutte le funzionalità e non sembra mai eliminare tutti i bug.

Stiamo facendo test unitari errati quando sembra che non stiamo ancora verificando il software correttamente prima della distribuzione? Oppure la maggior parte dei negozi ha un altro livello di test automatici oltre ai test unitari?

    
posta Peter Smith 22.08.2014 - 20:32
fonte

6 risposte

7

In generale no. Per i programmi giocattolo (ad esempio le soluzioni ai problemi di Project Euler), sicuro.

Questo è prima di entrare in una discussione religiosa su cosa sono i test unitari (se usa un oggetto file system, è un test unitario? Lascia che l'inquisizione abbia inizio!)

Per le applicazioni N-Tier, dove N > 1, sono necessari test di integrazione, e anche loro potrebbero non essere effettivamente adatti per la verifica dei requisiti, poiché la maggior parte dei test di integrazione sono tra due livelli, e non normalmente i test end-to-end. La maggior parte dei test end-to-end (un test minimo per la maggior parte dei requisiti) viene solitamente eseguita come / in concomitanza con il test a livello di sistema.

In un grande progetto su cui ho lavorato, abbiamo avuto CUT (Code e Unit Test) svolto dallo sviluppatore. Il codice di build è stato quindi integrato in Integration and Test (I & T), in cui sono stati verificati alcuni requisiti minori (gli avvisi di avviso verranno visualizzati in "FUNKY_RED" nella console di amministrazione). Al suo superamento, è stato rilasciato a System Level Test (SLT). Il 'Test dei requisiti' è stato fatto in SLT, dove avevano uno specchio del sito operativo. Alla fine, è stato distribuito ed è andato a Acceptance Test.

Alcuni di questi cambieranno, a seconda della scala del progetto. Ma nella mia esperienza, qualsiasi cosa con più di un modulo / jar / libreria non sarà sufficiente con i soli test di unità.

Aggiungi test di una GUI e diventa davvero improbabile che tu possa avere il 100% di confidenza senza interazione dal vivo.

EDIT: Guardando indietro, ritengo che per i sistemi complessi sia necessario che test semplici (come i test unitari) non siano sufficienti per la convalida dei requisiti. I sistemi complessi richiedono test complessi (sofisticati?) Da verificare.

    
risposta data 22.08.2014 - 20:49
fonte
5

Hai diverse cose da considerare:

  1. I requisiti devono essere testabili. Se non sono testabili, non puoi verificarli con i test.

  2. I test unitari non sono una prova di correttezza , principalmente perché non possono fornire una copertura del codice del 100% in alcun modo pratico.

Il primo punto è abbastanza facile da correggere, se è difficile da implementare nella pratica: rendere testabili i requisiti . Il modo migliore per farlo è definire un test di accettazione nello stesso momento in cui scrivi il requisito.

Il secondo punto solleva la domanda: "Come posso scrivere un software più affidabile?" Questo, amico mio, è oggetto di una vita di studio.

Tuttavia, dal punto di vista dei test, puoi migliorare la situazione aggiungendo Test di integrazione e Test di livello di sistema. I test unitari, da soli, sono spesso insufficienti per descrivere una rigorosa suite di test. Lavora con i tuoi stakeholder per definire e scrivere test, portata, costi e benefici di cui tutti comprendono.

    
risposta data 22.08.2014 - 20:52
fonte
3

Per testare completamente un sistema, dovresti sottoporlo a tutte le possibili serie di condizioni di input, quindi per qualsiasi sistema non giocattolo, non è possibile che nessun sistema di test sia in grado di rilevare tutti gli errori.

Tuttavia, questo è un caso in cui la perfezione è il nemico di "abbastanza buono". Se un sistema di test riduce la possibilità di spedire un prodotto difettoso, o riduce il numero di difetti spediti, o riduce il tempo necessario per testare un sistema prima che venga spedito, ha un valore.

Il semplice fatto di disporre di "corpi di test di unità di grandi dimensioni con una copertura di linea ragionevole" non garantisce il codice privo di errori. Tuttavia, probabilmente è molto meglio di nessun sistema di test.

Si noti che il test dell'unità è solo un tipo di test del software. Non sarebbe male neanche creare alcuni test di integrazione automatica. Non solo, quando sto per rilasciare una nuova versione del software, controllo sempre manualmente che posso fare un paio di funzioni critiche, per ogni evenienza.

    
risposta data 22.08.2014 - 20:49
fonte
1

La fase "test unitario" è iniziata come descrizione di test delle singole funzioni e altri piccoli bit di codice / capacità. Se questo è tutto ciò che stai testando - bit di il tuo sistema, in isolamento l'uno dall'altro, non c'è da meravigliarsi se stai perdendo la fiducia nei test per essere una misura corretta della qualità complessiva del codice o "lo fa fa quello che dovrebbe fare? "

Il test molto ristretto aiuta un po ', ma solo un po'. E 'fantastico che tu non stanno ottenendo fallimenti di produzione che riconducono a cose che sono state testato. Il problema sembra essere lo spazio bianco intermedio: non testato percorsi di esecuzione, la combinazione di elementi che si verificano quando tutte le parti venire insieme che non sono attualmente testati. Senza essere troppo Pollyannaish, c'è il tuo problema O una buona parte di esso, in ogni caso.

Questa è forse un'eresia, ma ha funzionato bene per me: i test unitari non sono più su unità isolate e strette. Sono un test automatizzato per scopi generici funzionalità che può e deve testare non solo singole funzioni, classi e oggetti, ma combinazioni di essi, a vari livelli di composizione.

Potrei aver eseguito PHPUnit o py.test o qualunque sia il "test unitario" locale il framework è, ma aggiungo con entusiasmo test fino a includere test dell'intero applicazione o servizio integrati. Eseguo esempi complessi dell'intera app funzionalità, e farlo non solo contro semplici casi di dati, ma anche contro alcuni casi estremi, brutti, complessi.

Non è così facile testare in questo modo. Richiede la creazione di alcuni simulare oggetti e / o costruire interi macchine virtuali e popolarle con server, set di dati e altra colla logica solo per eseguire i test. È più lavoro impostare questo scenario di test, ma con istanze di virtualizzazione e cloud, strumenti come Fabric e Vagrant rendono è fattibile in modi che non era, cinque anni indietro.

Può persino essere complicato determinare se un test ha avuto esito positivo o negativo. Se tu sei usato per testare piccole funzioni, è difficile capire perché - ma inizia a provare a giudicare se hai manipolato correttamente una struttura dati complessa e diventa più chiaro. Può essere anche peggio se stai cercando di vedere un particolare percorso attraverso a GUI o web app per assicurarsi che "abbia fatto quello che doveva fare". Ma con il moderno strumenti, è possibile - ed i risultati sono estremamente utili nell'esercitare il intero sistema.

Il test non può mai essere una prova di correttezza in tutte le possibili condizioni. Ma esercitando la tua app o il servizio nel suo insieme, con un caso complesso e all'avanguardia esempi progettati per sottolineare la tua logica ... prima ti mostrerà dove sono molti i tuoi bug mentono ("La verità ti renderà libero - ma prima ti renderà miserabile ".)

Ma mentre aggiusti quelli e il tuo sistema sta eseguendo con successo casi difficili e di routine, allora crescerà la tua fiducia nella sua correttezza e robustezza. Quando trovi nuovi bug e li correggi, aggiungerai test per loro e altri casi come loro non avevi precedentemente considerato. Su passaggi successivi al test lavoro, troverai nuove cose che vuoi testare o nuove varianti che vuoi testare contro. Li aggiungi e, dopo la corsa, stai testando ancora di più del totale sistema.

Se qualcuno vuole sostenere che non sono davvero un test unitario, ne sto facendo un po ' forma di integrazione, modulo o test di sistema - bene qualunque cosa! Io uso lo stesso (unit test) quadri, test runner, "è passato?" riferendo che lo farei per testare una funzione a 2 linee. Se vuoi dare nomi più elaborati per alcuni dei prova, buttati fuori. Quello che mi interessa è che i test sono automatizzati, che posso eseguirli facilmente per ogni build di software e che testano tanto della funzionalità totale possibile.

Per farla breve, invece di perdere la fiducia nei test, raddoppia. Fai il test di cui hai bisogno, ma al momento non lo stai facendo. Metti alla prova le cose insieme, sempre combinazioni più impegnative e complete, contro sempre più esecuzione ambienti. Rimarrai stupito dagli insetti che si agitano e da quanto sei tu scopri di conseguenza le interazioni del tuo sistema. Intempestivamente, sarai sbalordito su come ti muovi con sicurezza dalla versione alla versione, perché il tuo shakedown è stato reale e sistematico.

    
risposta data 23.08.2014 - 00:13
fonte
1

In effetti, come hai trovato, i test unitari sono spesso inadeguati per questo.

Ciò di cui hai bisogno è un test integrato che cercherà di testare:

  • dipendenze
  • interazioni
  • diversi dispositivi / piattaforme di visualizzazione / versioni

Potrebbe anche essere necessario rivisitare i test unitari e verificare quanto spesso il percorso triste (al contrario del percorso felice) sia in fase di test. Gli sviluppatori si concentrano spesso su un percorso felice ma spesso non anticipano o si prendono il tempo per occuparsi di casi complessi e di tutti i tristi percorsi.

    
risposta data 23.08.2014 - 00:27
fonte
-1

We have large unit test bodies that have reasonable line coverage but almost all of these focus on individual classes and not on their interactions.

Nella mia esperienza, ciò è causato da un design di classe scadente e, occasionalmente, da una cattiva scrittura del test unitario.

In un mondo ideale (raggiungibile), la classe di test dell'unità A: prende l'input corretto e produce l'output corretto. Quindi il test unitario di classe B: prende l'input corretto e produce l'output corretto. Se l'output "giusto" della classe A viene alimentato come input "giusto" per la classe B, allora funzionerà.

L'unico modo in cui le cose vanno a sud è se la tua classe definisce una definizione sfumata di "giusto" a causa dell'accoppiamento implicito in dati o tempo o sequenza o ... È qui che entra in gioco il design di una buona classe. Riducendo il tuo accoppiamento e rendendo più chiaro il tuo input "giusto", ci sono meno possibilità che le persone possano rovinare tutto.

L'altra cosa che può succedere è che i test delle tue unità funzionano con un uso ingenuo di "giusto" che non verifica i limiti, o che effettivamente esercita il tuo codice pur ottenendo la copertura del codice. I test sbagliati porteranno a risultati negativi, il peggiore dei quali sarà il test che non dà confidenza.

    
risposta data 22.08.2014 - 21:54
fonte

Leggi altre domande sui tag