Testare il tuo codice è fastidioso, ma l'impatto di non farlo può essere di ordine di grandezza più fastidioso! In questo articolo, utilizzeremo lo sviluppo basato su test per scrivere e testare il nostro codice in modo più efficace.
Sin dagli albori dell'era dei computer, i programmatori e gli insetti hanno combattuto per la supremazia. È un evento inevitabile. Persino i più grandi programmatori sono preda di queste anomalie. Nessun codice è sicuro. Ecco perché facciamo test. I programmatori, almeno quelli sane, testano il loro codice eseguendolo su macchine di sviluppo per assicurarsi che faccia quello che dovrebbe.
Sviluppo guidato dai test è una tecnica di programmazione che richiede di scrivere contemporaneamente codice reale e codice di test automatizzato. Ciò garantisce di testare il codice e consente di ripetere il test del codice in modo rapido e semplice, poiché è automatizzato.
Lo sviluppo basato sui test, o TDD come lo chiameremo da ora in poi, ruota attorno a un breve ciclo di sviluppo iterativo che va in questo modo:
Hai mai intenzionalmente saltato il test di un programma perché:
La maggior parte delle volte, non succede nulla, e si sposta con successo il proprio codice in produzione senza problemi. Ma a volte, dopo essere passati alla produzione, tutto va storto. Sei bloccato a fissare un centinaio di buche in una nave che affonda, con più apparizioni ogni minuto. Tu fai non voglio trovarti in questa situazione.
TDD aveva lo scopo di eliminare le nostre scuse. Quando un programma è stato sviluppato utilizzando TDD, ci consente di apportare modifiche e test in modo rapido ed efficiente. Tutto quello che dobbiamo fare è eseguire i test automatici e voilà! Se passa tutti i test automatici, allora siamo a posto, se no, significa solo che abbiamo rotto qualcosa con le modifiche. Sapendo quali parti esatte del test hanno fallito, ci permette anche di individuare facilmente la parte delle modifiche che ha rotto, quindi rende più facile la correzione degli errori.
C'è una moltitudine di framework di test automatici di PHP che possiamo usare. Uno dei framework di test più diffusi è PHPUnit.
PHPUnit è un ottimo framework di testing, che può essere facilmente integrato nei tuoi progetti, o altri progetti costruiti su framework PHP popolari.
Per i nostri scopi, tuttavia, non avremo bisogno della moltitudine di funzioni offerte da PHPUnit. Invece, opteremo per creare i nostri test usando un framework di test molto più semplice, chiamato SimpleTest.
Nei prossimi passi, supponiamo che stiamo sviluppando un'applicazione guestbook in cui ogni utente può aggiungere e visualizzare le voci del guestbook. Supponiamo che il markup sia stato completato e che stiamo semplicemente facendo una classe che contiene il logica applicativa del guestbook, che è il punto in cui l'applicazione inserisce e legge nel database. La porzione di lettura di questa classe è ciò che svilupperemo e testeremo.
Questo è senza dubbio il passo più facile di tutti. Anche questo ragazzo potrebbe farlo:
Scarica SimpleTest qui, ed estrai in una cartella a tua scelta - preferibilmente la cartella in cui svilupperai il tuo codice, o il tuo PHP include_path per un facile accesso.
Per questo tutorial, ho impostato la cartella in questo modo:
Index.php eseguirà guestbook.php e invocherà il metodo di visualizzazione e visualizzerà le voci. All'interno della cartella classes è dove inseriremo la classe guestbook.php, e la cartella test è dove posizioniamo la libreria più semplice.
Il secondo passo, che è in realtà il più importante, è iniziare a creare i test. Per questo, hai davvero bisogno di pianificare e pensare a cosa farà la tua funzione, quali input possibili otterrà e gli output corrispondenti che invierà. Questo passaggio assomiglia a una partita a scacchi: devi sapere tutto sul tuo avversario (il programma), comprese tutte le sue debolezze (possibili errori) e punti di forza (cosa succede se funziona correttamente).
Quindi per la nostra applicazione guestbook, stabiliamo gli schemi:
Array ([0] => Array (['name'] = "Bob" ['message'] = "Ciao, sono Bob.") [1] => Array (['name'] = "Tom" ['message'] = "Ciao, sono Tom.")))
Ora possiamo scrivere il nostro primo test. Iniziamo creando un file chiamato guestbook_test.php all'interno della cartella test.
Quindi, convertiamo ciò che abbiamo determinato dal passaggio due,.
aggiungi ("Bob", "Ciao, sono Bob."); $ guestbook-> add ("Tom", "Ciao, sono Tom."); $ entries = $ guestbook-> viewAll (); $ count_is_greater_than_zero = (count ($ entries)> 0); $ This-> assertTrue ($ count_is_greater_than_zero); $ this-> assertIsA ($ entries, 'array'); foreach ($ entries come $ entry) $ this-> assertIsA ($ entry, 'array'); $ This-> assertTrue (isset ($ entry [ 'name'])); $ This-> assertTrue (isset ($ entry [ 'messaggio'])); function testViewGuestbookWithNoEntries () $ guestbook = new Guestbook (); $ Guestbook-> CancTutti (); // Elimina prima tutte le voci in modo che sappiamo che è una tabella vuota $ entries = $ guestbook-> viewAll (); $ this-> assertEqual ($ entries, array ());Le asserzioni assicurano che una certa cosa sia ciò che dovrebbe essere, in sostanza, assicura che ciò che viene restituito è ciò che ti aspetti che ritorni. Per esempio, se una funzione dovrebbe restituire true se ha successo, allora nel nostro test, dovremmo affermare che il valore restituito è uguale a true.
Come puoi vedere qui, testiamo la visualizzazione del guestbook con le voci e senza. Controlliamo se questi due scenari superano i nostri criteri dal secondo passaggio. Probabilmente hai anche notato che ciascuna delle nostre funzioni di test inizia con la parola "test". L'abbiamo fatto perché, quando SimpleTest esegue questa classe, cercherà tutte le funzioni che iniziano con la parola 'test' ed eseguirla.
Nella nostra classe di test, abbiamo anche utilizzato alcuni metodi di asserzione, come assertTrue, assertIsA e assertEquals. La funzione assertTrue verifica se un valore è vero o no. AssertIsA controlla se una variabile è di un certo tipo o classe. Infine, assertEquals verifica se una variabile è totalmente uguale a un certo valore.
Esistono altri metodi di asserzione forniti da SimpleTest, che sono:
assertTrue ($ x) | Fallisce se $ x è falso |
assertFalse ($ x) | Fallisce se $ x è vero |
assertNull ($ x) | Fallisce se $ x è impostato |
assertNotNull ($ x) | Fallisce se $ x non è impostato |
assertIsA ($ x, $ t) | Fallisce se $ x non è la classe o il tipo $ t |
assertNotA ($ x, $ t) | Fallisce se $ x è della classe o del tipo $ t |
assertEqual ($ x, $ y) | Fallisce se $ x == $ y è falso |
assertNotEqual ($ x, $ y) | Fallisce se $ x == $ y è vero |
assertWithinMargin ($ x, $ y, $ m) | Fallire se abs ($ x - $ y) < $m is false |
assertOutsideMargin ($ x, $ y, $ m) | Fallire se abs ($ x - $ y) < $m is true |
assertIdentical ($ x, $ y) | Fallisce se $ x == $ y è falso o un tipo non corrispondente |
assertNotIdentical ($ x, $ y) | Fallisce se $ x == $ y è vero e i tipi corrispondono |
assertReference ($ x, $ y) | Fallire a meno che $ x e $ y siano la stessa variabile |
assertClone ($ x, $ y) | Fallire a meno che $ x e $ y siano copie identiche |
assertPattern ($ p, $ x) | Fallisci a meno che l'espressione regolare $ p corrisponda a $ x |
assertNoPattern ($ p, $ x) | Fallisce se l'espressione regolare $ p corrisponde a $ x |
expectError ($ x) | Ingoia qualsiasi errore di corrispondenza imminente |
affermare ($ e) | Errore nell'oggetto aspettativa fallita $ e |
Elenco dei metodi di asserzione per gentile concessione di http://www.simpletest.org/en/unit_test_documentation.html
Una volta che hai finito di scrivere il codice, devi eseguire il test. La prima volta che esegui il test, DOVREBBE FALLISCI. Se non lo fa, vuol dire che il test in realtà non prova nulla.
Per eseguire il test, è sufficiente eseguire guestbook_test.php nel tuo browser. Dovresti vedere prima questo:
Ciò è accaduto perché non abbiamo ancora creato la nostra lezione per gli ospiti. Per fare ciò, crea guestbook.php all'interno della tua cartella delle classi. La classe dovrebbe contenere i metodi che intendiamo utilizzare, ma non dovrebbe contenere ancora nulla all'inizio. Ricorda, stiamo scrivendo prima i test prima scrivendo qualsiasi codice.
Quando si esegue nuovamente il test, dovrebbe essere simile a questo:
Come possiamo vedere qui, il nostro test ora sta vincendo fallendo. Ciò significa che il nostro test è ora pronto per ricevere "risposta".
Immagine gentilmente concessa da http://www.gamercastnetwork.com/forums
Passaggio 5. Rispondere al test scrivendo il codice
Ad un certo punto, ci siamo sentiti tutti così quando stiamo programmando.
Immagine per gentile concessione di http://fermentation.typepad.com/it/fermentationOra che abbiamo un test automatico funzionante, possiamo iniziare a scrivere codice. Apri il tuo guestbook.php classe e inizia a creare la risposta al tuo test.
'Kirk', 'message' => 'Ciao, sono Kirk.' ), array ('name' => 'Ted', 'message' => 'Ciao, sono Ted.')); public function viewAll () // Qui, dovremmo recuperare tutti i record dal database. // Questo viene simulato restituendo l'array $ _entries return self :: $ _; public function add ($ name, $ message) // Qui, simuliamo l'inserimento nel database aggiungendo un nuovo record nell'array $ _entries // Questo è il modo corretto di farlo: self :: $ _ entries [] = array ('nome' => $ nome, 'messaggio' => $ messaggio); self :: $ _ entries [] = array ('notname' => $ name, 'notmessage' => $ message); // oops, c'è un bug qui da qualche parte restituisce true; public function deleteAll () // Abbiamo appena impostato la matrice $ _entries per simulare self :: $ _ entries = array (); ritorna vero;Questa classe guestbook.php ha alcuni bug in proposito, quindi possiamo vedere come appare se il nostro test fallisce.
Una volta eseguito il test, dovremmo vedere qualcosa di simile a questo:
L'output del test ci mostra in quale test e in quale asserzione il nostro codice ha fallito. Da questo, possiamo facilmente individuare che la riga 16 e 17 era l'affermazione che ha gettato l'errore.
assertTrue (isset ($ entry [ 'name'])); $ This-> assertTrue (isset ($ entry [ 'messaggio'])) ;?Questo ci dice chiaramente che l'array di input restituito non aveva la chiave dell'array corretta. Sulla base di questo, sapremo facilmente quale parte del nostro codice è andata storta.
$ nome, 'messaggio' => $ messaggio); //fisso! ritorna vero; ?Ora, quando eseguiremo di nuovo il nostro test, dovrebbe mostrarci:
Passaggio 6. Refactor e perfezionare il codice
Immagini per gentile concessione di http://www.osborneink.com e http://phuketnews.phuketindex.comDato che il codice che stiamo testando qui è piuttosto semplice, i nostri test e bug fixing non sono durati molto a lungo. Ma se questa fosse un'applicazione più complessa, dovresti apportare più modifiche al codice, renderlo più pulito, quindi è più facile da mantenere e molte altre cose. Il problema con questo, però, è che il cambiamento di solito introduce bug aggiuntivi. È qui che entra in gioco il nostro test automatizzato: una volta apportate le modifiche, possiamo semplicemente eseguire nuovamente il test. Se passa ancora, vuol dire che non abbiamo infranto nulla. Se fallisce, sappiamo che abbiamo commesso un errore. Ci informa anche dove si trova il problema e, si spera, in che modo riusciremo a risolverlo.
Passaggio 7. Risciacquare e ripetere
Immagine per gentile concessione di http://www.philstockworld.comAlla fine, quando il tuo programma richiede nuove funzionalità, dovrai scrivere nuovi test. Questo è facile! Risciacquare e ripetere le procedure del passaggio 2 (poiché i file SimpleTest dovrebbero già essere impostati) e riavviare il ciclo da capo.
Conclusione
Esistono molto più approfonditi articoli di sviluppo basati sui test, e ancora più funzionalità di SimpleTest rispetto a ciò che è stato mostrato in questo articolo: cose come oggetti mock, stub, che rendono più facile la creazione di test. Se desideri saperne di più, la pagina di sviluppo guidata da test di Wikipedia dovrebbe metterti sulla giusta strada. Se si desidera utilizzare SimpleTest come framework di test, consultare la documentazione in linea e assicurarsi di rivedere le sue altre funzionalità.
I test sono parte integrante del ciclo di sviluppo, tuttavia, è troppo spesso la prima cosa da tagliare quando le scadenze sono imminenti. Spero che, dopo aver letto questo articolo, apprezzerai quanto sia utile investire nello sviluppo basato sui test.
Quali sono le tue opinioni su Test-Driven Development? È qualcosa che ti interessa implementare o pensi che sia una perdita di tempo? Fatemi sapere nei commenti!