L'idea centrale di Test-Driven Development (TDD) è scrivere test prima di scrivere qualsiasi codice funzionale e quindi scrivere solo la quantità minima di codice richiesta per far passare i test. Può sembrare strano svilupparsi in questo modo, ma in realtà è abbastanza utile, dato che la base di test funge anche da specifica parziale del codice principale.
Data una premessa così semplice, tuttavia, esiste una quantità incredibile di terminologia e tecniche. In questo articolo, raccolgo i termini e le parole chiave più importanti che potresti sentire e li definisco.
La programmazione test-first consente test funzionali di alto livello.
Il più alto livello di test convalida che il software soddisfa i requisiti del cliente. I test di accettazione vengono comunemente eseguiti in ambienti il più possibile vicini alla produzione. Vedi test funzionali e test di sistema.
Le asserzioni sono affermazioni che eseguono un controllo effettivo sull'output del software. In generale, una singola funzione chiamata affermare
è sufficiente per esprimere qualsiasi controllo In pratica, le librerie di test hanno spesso molte funzioni di asserzione per soddisfare esigenze specifiche (come ad es assertFalse
, assertEqual
e altro ancora) per offrire una migliore analisi e un output più amichevole.
Una tecnica di test che incorpora il test raddoppia al software, affermando che chiama i metodi corretti in un ordine corretto. Vedi finto per un esempio. Vedi anche test di stato.
Un sottoinsieme di TDD guidato dalla necessità di una comunicazione più chiara e di una documentazione adeguata. BDD è forse il più grande sviluppo recente in TDD.
La sua idea centrale è quella di sostituire la terminologia confusa e incentrata sullo sviluppatore (test, suite, asserzioni ecc) con linguaggio ubiquo che tutti gli stakeholder partecipanti (compreso lo staff non tecnico e, possibilmente, i clienti) possono capire.
Vedi la storia dell'utente.
Un principio generale nel test in cui la persona che scrive i test non conosce o evita le parti interne del software, scegliendo invece di testare l'interfaccia pubblica del software rigorosamente dalla sua interfaccia o dalle sue specifiche. Vedi test white-box.
Una strategia per scrivere test per rilevare errori di tipo off-by-one e altri simili. Per eseguire test del valore limite, testare gli input attorno a determinati limiti potenzialmente problematici. In caso di numeri interi, questo potrebbe essere 0
, -1
, MIN_INT
, MAX_INT
e altri valori simili.
Le asserzioni sono affermazioni che eseguono un controllo effettivo sull'output del software.
Un manichino è un tipo di test double che non viene mai utilizzato dal software attuale, ma viene utilizzato solo nei test per riempire i parametri richiesti.
I falsi sono duplicati di prova che implementano la funzionalità richiesta in un modo che è utile per il test, ma che lo squalifica efficacemente dall'essere utilizzato nell'ambiente di produzione. Ad esempio, un database di valori-chiave che memorizza tutti i valori in memoria e li perde dopo ogni esecuzione potenzialmente consente ai test di essere eseguiti più rapidamente, ma la sua tendenza a distruggere i dati non gli consentirebbe di essere utilizzato in produzione.
Un particolare ambiente che deve essere impostato prima di poter eseguire un test. Generalmente consiste nell'impostare tutti i duplicati di test e altre dipendenze per il software in prova: come inserire dati predefiniti in un database falso, impostare una determinata struttura di directory nel file system falso, impostare le proprietà sulle dipendenze del software in prova.
Un'attività di test di alto livello che verifica che vengano soddisfatti tutti i requisiti aziendali del prodotto. I test funzionali implicano l'uso di storie utente per concentrarsi su un livello più alto di requisiti per coprire il maggior numero possibile di scenari di utilizzo. Vedi test di accettazione e test di sistema. Per esempio:
# In questo esempio controlliamo che la pagina relativa del sito web funzioni come previsto open "esempio.com" clickOn "about us" assertThereIs "We are a small Example company"
Un colloquialismo per una raccolta di test di passaggio, o qualche volta un particolare test di passaggio. Vedere rosso.
Un'attività di test di livello intermedio che verifica che un determinato insieme di moduli funzioni correttamente insieme. I test di integrazione sono come test unitari senza utilizzare i doppi di prova per un determinato sottoinsieme di dipendenze, testando essenzialmente le interazioni tra il software e le sue dipendenze. Esempio:
# In questo esempio controlliamo che l'utente appena registrato, # che è stato indirizzato da un altro utente, abbia creato una "amicizia" sul posto. # Qui controlliamo l'interazione tra il form controller, # database e un record attivo dell'utente db = new Fake Db u1 = db.createUser (name = 'john') RegistrationForm (db, name = "kate", references = "john ") .save () assert (u1.hasFriend ('kate'))
Un tipo di doppio di prova creato per un particolare test o caso di test. Si aspetta di essere chiamato un numero specifico di volte e dà una risposta predefinita. Alla fine del test, un mock genera un errore se non è stato chiamato tante volte quanto previsto. Una finta con aspettative rigide fa parte del quadro di asserzione. Esempio:
# In questo esempio utilizziamo un database fittizio per verificare che il modulo # usi il database per memorizzare il nuovo utente. # Se il database non è stato chiamato alla fine del test, # il mock stesso genererà un errore di asserzione. db = new Mock Db db.expect ('save'). once (). con (name = 'john') RegistrationForm (db, name = "john"). save ()
Un modo per estendere e modificare il comportamento degli oggetti e delle classi esistenti in un linguaggio di programmazione. Le patch di scimmia possono essere utilizzate come alternativa all'iniezione di dipendenza e ai duplicati di test modificando direttamente le funzioni esistenti chiamate dal software in prova (e modificandole dopo il test).
# In questo esempio sostituiamo la funzione di libreria standard # per impedire al test di utilizzare un filesystem reale filesystem.listdir = f (nome) -> ['.', '...', 'foo', 'bar']; assertEqual (MyFileSearch ('foo'). count (), 1)
Un colloquialismo per una collezione fallita di test o, a volte, per un particolare test fallimentare. Vedi verde.
Il processo di miglioramento dei dettagli di implementazione del codice senza modificarne la funzionalità.
Refactoring senza test è un processo molto fragile, in quanto lo sviluppatore che fa il refactoring non può mai essere sicuro che i suoi miglioramenti non stiano rompendo alcune parti della funzionalità.
Se il codice è stato scritto utilizzando lo sviluppo basato su test, lo sviluppatore può essere certo che il suo refactoring è andato a buon fine non appena tutti i test passano, poiché tutte le funzionalità richieste del codice sono ancora corrette.
Un difetto software che appare in una particolare caratteristica dopo un evento (di solito un cambiamento nel codice).
Test di scenario
Vedi test funzionali.
Un processo di preparazione di un dispositivo. Vedi teardown. Esempio:
# In questo esempio prepariamo un falso database con alcuni valori falsi # che saranno necessari attraverso test multipli db = new Fake Db db.createUser (name = 'john') db.createUser (name = 'kate') db.createFriendship ( 'john', 'kate')
Una forma di test unitario quando il codice di test fornisce il doppio del test e asserisce che lo stato di questi doppi è stato modificato in modo corretto. Vedi test di comportamento.
# In questo esempio, come in un esempio su oggetti mock, # controlleremo che il modulo utilizzi il database per memorizzare il nuovo utente. # Questa volta controlleremo lo stato, invece del comportamento db = new Fake Db RegistrationForm (db, name = "john"). Save () assertInList ('john', db.listUsers ())
I falsi sono duplicati di test che non vengono mai utilizzati dal software attuale.
Un tipo di test double che può rispondere al software in fase di test con risposte predefinite. A differenza dei mock, tuttavia, gli stub di solito non controllano se sono stati chiamati correttamente, ma piuttosto si assicurano che il software possa chiamare le sue dipendenze.
Un'attività di test di alto livello quando tutta la parte del software viene testata dall'inizio alla fine. Questo include test funzionali, oltre a controllare altre caratteristiche (come prestazioni e stabilità).
Un'abbreviazione per software sotto test. Utilizzato per distinguere il software in prova dalle sue dipendenze.
Un processo di pulizia di un dispositivo. Nei linguaggi raccolti con garbage, questa funzionalità viene gestita principalmente in modo automatico. Vedi setup.
Il più piccolo controllo possibile per la correttezza. Ad esempio, un singolo test per un modulo Web potrebbe essere un controllo che, quando viene fornito un indirizzo email non valido, il modulo avverte l'utente e suggerisce una correzione. Vedi caso di test.
Una raccolta di test raggruppati per un attributo. Ad esempio, un test case per un modulo Web potrebbe essere una raccolta di test che verificano il comportamento del modulo per diversi input validi e non validi.
funzione t1: assertNoError (RegistrationForm (name = 'john', password = "horse battery staple correct"). save ()) function t2: assertError (funzione MissingPassword, RegistrationForm (name = 'john'). save ()) t3: assertError (StupidPassword, RegistrationForm (name = 'john', password = "password"). save ())
Le storie utente sono generalmente definite in lingue umane per concentrarsi invece sull'esperienza utente.
Qualsiasi tipo di metrica che tenta di stimare la probabilità di un comportamento importante del SUT non è ancora coperto dai test. Le tecniche più popolari includono diversi tipi di copertura del codice: tecniche che assicurano che tutte le possibili istruzioni di codice (o funzioni, o rami logici nel codice) siano state eseguite durante il test.
Un processo di sviluppo TDD. Dato che lo sviluppo di TDD inizia con la scrittura di alcuni test, è chiaro che la suite di test si avvia in rosso. Non appena lo sviluppatore implementa tutte le funzionalità appena testate, i test diventano verdi. Ora lo sviluppatore può refactoring sicuro la sua implementazione senza il rischio di introdurre nuovi bug, in quanto ha una suite di test su cui fare affidamento. Una volta completato il refactoring, lo sviluppatore può riavviare il ciclo scrivendo altri test per ulteriori nuove funzionalità. Quindi, il ciclo di prova red-green-refactor.
Test doppio
I duplicati di prova sono oggetti creati dal codice di prova che passano al SUT per sostituire le dipendenze reali. Ad esempio, i test unitari dovrebbero essere molto veloci e testare solo un particolare software.
Per queste ragioni, le sue dipendenze, come le librerie di interazione di un database o di un file system, vengono solitamente sostituite da oggetti che agiscono in memoria invece di parlare con un vero database o un file system.
Ci sono quattro categorie principali di duplicati di test: manichini, falsi, matrici e mock.
Una raccolta di casi di test che testano una gran parte del software. In alternativa, tutti i casi di test per un particolare software.
Il test white-box consente un'analisi più approfondita dei possibili problemi nel codice.
La programmazione test-first è un termine leggermente più ampio per lo sviluppo basato sui test. Mentre TDD promuove l'accoppiamento stretto tra i test di scrittura (in genere test di unità) e la scrittura del codice, la programmazione test-first consente invece di eseguire test funzionali di alto livello. Tuttavia, la distinzione nell'uso generale è raramente notata, e due i termini sono solitamente usati in modo intercambiabile.
La tecnica di test di livello più basso costituita da test case per le unità di codice più piccole possibili. Un singolo test unitario di solito verifica solo un particolare comportamento di piccole dimensioni e un caso di test unitario di solito copre tutte le funzionalità di una particolare singola funzione o classe.
Una singola descrizione di un particolare gruppo di persone disposte a svolgere un compito particolare utilizzando il SUT per raggiungere un obiettivo particolare. Le storie degli utenti sono solitamente definite in lingue umane, utilizzando termini semplici e incentrati sull'utente per evitare di considerare i dettagli dell'implementazione e concentrarsi invece sull'esperienza utente. Per esempio:
Come utente, voglio essere in grado di trovare i miei amici su questo sito dalla mia rubrica, invece di cercarli uno per uno, perché questo mi farà risparmiare un sacco di tempo.
Il test white-box è una tecnica di test quando una persona che esegue il test conosce o può leggere gli interni del SUT. A differenza dei più comuni test black-box, i test white-box consentono un'analisi più approfondita dei possibili problemi nel codice.
Ad esempio, un particolare valore limite potrebbe non assomigliare a uno basato esclusivamente sulle specifiche del software, ma potrebbe essere ovvio dall'implementazione di esso.
Inoltre, qualsiasi tecnica di copertura del test di solito è, per definizione, parte del test white-box.