Å teste koden din er irriterende, men virkningen av å ikke gjøre det kan være størrelsesordre mer irriterende! I denne artikkelen bruker vi testdrevet utvikling for å skrive og teste vår kode mer effektivt.
Siden begynnelsen av datatiden har programmører og insekter kjempet for overlegenhet. Det er en uunngåelig forekomst. Selv de største programmørene blir bytte til disse anomaliene. Ingen kode er trygt. Det er derfor vi tester. Programmerere, minst sane, teste koden ved å kjøre den på utviklingsmaskiner for å sikre at den gjør hva den skal.
Testdrevet utvikling er en programmeringsteknikk som krever at du skriver faktisk kode og automatisk testkode samtidig. Dette sikrer at du tester koden din - og lar deg omprøve koden raskt og enkelt, siden det er automatisert.
Testdrevet utvikling, eller TDD som vi kaller det fra nå av, dreier seg om en kort iterativ utviklingssyklus som går noe slikt:
Har du noen gang forsøkt hoppet over å teste et program fordi:
Mesteparten av tiden skjer ingenting, og du flyttes koden din til produksjon uten problemer. Men noen ganger, etter at du har flyttet til produksjon, går alt galt. Du sitter fast ved å fikse hundre hull i et synkende skip, med flere som vises hvert minutt. Du gjør ikke ønsker å finne deg selv i denne situasjonen.
TDD var ment å eliminere våre unnskyldninger. Når et program er utviklet ved hjelp av TDD, lar det oss gjøre endringer og teste raskt og effektivt. Alt vi trenger å gjøre er å kjøre automatiserte tester, og voila! Hvis det passerer alle automatiserte tester, så er det bra å gå - hvis ikke, så betyr det bare at vi har slått noe med endringene. Ved å vite hvilke eksakte deler av testen som ble feilet, gjør det oss også lett å finne ut hvilken del av endringene den brøt, så det gjør det enklere å fikse bugsene.
Det er en rekke PHP-automatiserte testrammer der ute som vi kan bruke. En av de mest brukte testrammene er PHPUnit.
PHPUnit er et flott testing rammeverk, som lett kan integreres i dine egne prosjekter, eller andre prosjekter bygget på toppen av populære PHP rammer.
For våre formål skjønt, trenger vi ikke det mangfold av funksjoner som PHPUnit tilbyr. I stedet velger vi å lage testene våre ved hjelp av et enklere testramme, kalt SimpleTest.
I de neste trinnene, la oss anta at vi utvikler en gjestebokprogram hvor noen brukere kan legge til og vise gjestebokoppføringer. La oss anta at markeringen er fullført, og at vi ganske enkelt lager en klasse som inneholder applikasjonslogikk i gjesteboken, som er der applikasjonen legger inn og leser til databasen. Leseplassen i denne klassen er hva vi skal utvikle og teste.
Dette er uten tvil det enkleste trinnet for alle. Selv denne fyren kunne gjøre det:
Last ned SimpleTest her, og trekk ut i en mappe av ditt valg - helst mappen der du skal utvikle koden din, eller din PHP include_path for enkel tilgang.
For denne opplæringen har jeg satt opp mappen slik:
Index.php vil kjøre guestbook.php, og påkalle visningsmetoden og vise oppføringene. Inne i klassen mappen er hvor vi skal sette guestbook.php-klassen, og testmappen er der vi plasserer det enkleste biblioteket.
Det andre trinnet, som faktisk er det viktigste, er å begynne å lage tester. For dette trenger du virkelig å planlegge og tenke på hva din funksjon vil gjøre, hvilke mulige innganger det vil få, og de tilsvarende utgangene det vil sende. Dette trinnet ligner å spille et sjakkspill - du må vite alt om motstanderen din (programmet), inkludert alle svakhetene (mulige feil) og styrker (hva skjer hvis det går bra).
Så for vår gjestebok søknad, la oss legge ned skjemaene:
Array (['name'] = "Bob" ['message'] = "Hei, jeg er Bob.") [1] => Array ['message'] = "Hei, jeg er Tom."))
Nå kan vi skrive vår første test. La oss begynne med å opprette en fil som heter guestbook_test.php inne i testmappen.
La oss da konvertere det vi har bestemt fra trinn to,.
legg til ("Bob", "Hei, jeg er Bob."); $ gjestebok-> legg til ("Tom", "Hei, jeg er Tom."); $ oppføringer = $ gjestebok-> viewAll (); $ count_is_greater_than_zero = (count ($ entries)> 0); $ Dette-> assertTrue ($ count_is_greater_than_zero); $ this-> assertIsA ($ entries, 'array'); foreach ($ oppføringer som $ entry) $ this-> assertIsA ($ entry, 'array'); $ Dette-> assertTrue (isset ($ entry [ 'name'])); $ Dette-> assertTrue (isset ($ oppføring [ 'beskjed'])); funksjon testViewGuestbookWithNoEntries () $ guestbook = ny gjestebok (); $ Guestbook-> Slett (); // Slett alle oppføringene først slik at vi vet at det er et tomt bord $ entries = $ guestbook-> viewAll (); $ this-> assertEqual ($ entries, array ());Påstandene sørger for at en viss ting er hva det skal være - i utgangspunktet sikrer det at det som returneres er det du forventer at det kommer tilbake. For eksempel, hvis en funksjon skal returnere sann hvis den lykkes, så i vår test, bør vi hevde at returverdi er lik sant.
Som du kan se her, tester vi visning av gjesteboken med oppføringer og uten. Vi kontrollerer om disse to scenariene overholder kriteriene fra trinn to. Du har sikkert også lagt merke til at hver av våre testfunksjoner starter med ordet "test". Vi gjorde dette fordi, når SimpleTest kjører denne klassen, vil den se etter alle funksjonene som starter med ordet "test" og kjøre det.
I vår testklasse har vi også brukt noen påstandsmetoder, for eksempel assertTrue, assertIsA og assertEquals. AssertTrue-funksjonen kontrollerer om en verdi er sann eller ikke. AssertIsA kontrollerer om en variabel er av en bestemt type eller klasse. Og til slutt kontrollerer assertEquals om en variabel er helt lik en viss verdi.
Det finnes andre påstandsmetoder levert av SimpleTest, som er:
assertTrue ($ x) | Feil hvis $ x er feil |
assertFalse ($ x) | Feil hvis $ x er sant |
assertNull ($ x) | Feil hvis $ x er satt |
assertNotNull ($ x) | Feil hvis $ x ikke er angitt |
assertIsA ($ x, $ t) | Feil hvis $ x ikke er klassen eller skriv $ t |
assertNotA ($ x, $ t) | Feil hvis $ x er av klassen eller skriv inn $ t |
assertEqual ($ x, $ y) | Feil hvis $ x == $ y er feil |
assertNotEqual ($ x, $ y) | Feil hvis $ x == $ y er sant |
assertWithinMargin ($ x, $ y, $ m) | Feil hvis abs ($ x - $ y) < $m is false |
assertOutsideMargin ($ x, $ y, $ m) | Feil hvis abs ($ x - $ y) < $m is true |
assertIdentical ($ x, $ y) | Feil hvis $ x == $ y er feil eller en type feilmatching |
assertNotIdentical ($ x, $ y) | Feil hvis $ x == $ y er sant og typer matcher |
assertReference ($ x, $ y) | Feil hvis ikke $ x og $ y er den samme variabelen |
assertClone ($ x, $ y) | Feil hvis ikke $ x og $ y er identiske kopier |
assertPattern ($ p, $ x) | Feil hvis ikke regex $ p matcher $ x |
assertNoPattern ($ p, $ x) | Feil hvis regex $ p samsvarer med $ x |
expectError ($ x) | Svelger eventuelle kommende samsvarsfeil |
hevde ($ e) | Feil på mislykket forventningsobjekt $ e |
Assertion method list med lov av http://www.simpletest.org/en/unit_test_documentation.html
Når du er ferdig med å skrive koden, bør du kjøre testen. Første gang du kjører testen, er det SKAL FØLGE. Hvis det ikke gjør det, betyr det at testen din ikke tester noe.
For å kjøre testen, bare kjøre guestbook_test.php i nettleseren din. Du bør se dette først:
Dette skjedde fordi vi ikke har opprettet vår gjesteboksklasse ennå. For å gjøre det, opprett guestbook.php i klassen din. Klassen skal inneholde metodene vi planlegger å bruke, men bør ikke inneholde noe ennå først. Husk at vi skriver tester først før skriver noen kode.
Når du kjører testen igjen, bør den se slik ut:
Som vi kan se her, vinner vår test nå ved å feile. Dette betyr at testen vår nå er klar til å bli "besvart".
Bilde med hilsen av http://www.gamercastnetwork.com/forums
Trinn 5. Svar på testen ved å skrive kode
På et tidspunkt har vi alle følt oss slik når vi programmerer.
Bilde med lov av http://fermentation.typepad.com/fermentationNå som vi har en fungerende automatisert test, kan vi begynne å skrive kode. Åpne opp din guestbook.php klasse og begynn å skape svaret på testen din.
'Kirk', 'message' => 'Hei, jeg er Kirk.' ), array ('name' => 'Ted', 'message' => 'Hei, jeg er Ted.')); offentlig funksjon viewAll () // Her bør vi hente alle poster fra databasen. // Dette simuleres ved å returnere $ _entries array Return Self: $ _ entries; offentlig funksjon legg til ($ navn, $ melding) // Her simulerer vi innføring i databasen ved å legge til en ny post i $ _entries-oppsettet // Dette er den riktige måten å gjøre det på: selv :: $ _ oppføringer [] = array ('name' => $ navn, 'message' => $ melding); selv: $ _ oppføringer [] = array ('notname' => $ navn, 'notmessage' => $ melding); // oops, det er en feil her et sted å returnere sant; offentlig funksjon deleteAll () // Vi har bare satt $ _entries array for å simulere selv: $ _ entries = array (); returnere sant;Denne guestbook.php-klassen har noen feil i det med vilje, så vi kan se hvordan det ser ut hvis vår test mislykkes.
Når vi kjører testen, bør vi se noe slikt:
Testutgangen viser oss i hvilken test og i hvilken påstand vår kode mislyktes. Fra dette kan vi enkelt finne ut at linjen 16 og 17 var påstanden som kastet feilen.
assertTrue (isset ($ entry [ 'name'])); $ Dette-> assertTrue (isset ($ oppføring [ 'beskjed'])) ;?Dette forteller oss tydelig at den returnerte oppføringsarmen ikke hadde den riktige oppsettnøkkelen. Basert på dette, vet vi lett hvilken del av koden vi gikk galt.
$ navn, 'melding' => $ melding); // fast! returnere sant; ?Nå, når vi kjører testen vår igjen, bør den vise oss:
Trinn 6. Refactor og Forbedre koden din
Bilder med lov av http://www.osborneink.com og http://phuketnews.phuketindex.comSiden koden vi tester her, er det ganske enkelt, ikke vår test- og bugfixering var lang. Men hvis dette var en mer komplisert applikasjon, må du gjøre flere endringer i koden din, gjør den renere, så det er lettere å vedlikeholde, og mange andre ting. Problemet med dette er imidlertid at forandringen vanligvis introduserer flere feil. Det er her vår automatiserte test kommer inn - når vi gjør endringer, kan vi bare kjøre testen igjen. Hvis det fortsatt går, betyr det at vi ikke brøt noe. Hvis det feiler, vet vi at vi har gjort en feil. Det informerer oss også hvor problemet er, og forhåpentligvis hvordan vi kan fikse det.
Trinn 7. Skyll og gjenta
Bilde med lov av http://www.philstockworld.comTil slutt, når programmet krever ny funksjonalitet, må du skrive nye tester. Det er enkelt! Skyll og gjenta prosedyrene fra trinn to (siden SimpleTest-filene dine allerede skal settes opp), og start syklusen igjen.
Konklusjon
Det er mange dypere testdrevne utviklingsartikler der ute, og enda mer funksjonalitet til SimpleTest enn det som ble vist i denne artikkelen-ting som mock objekter, stubber, som gjør det enklere å lage tester. Hvis du vil lese mer, bør Wikipedias testdrevne utviklingsside sette deg på riktig vei. Hvis du er ivrig etter å bruke SimpleTest som testramme, kan du bla gjennom online dokumentasjonen og være sikker på å se gjennom de andre funksjonene.
Testing er en integrert del av utviklingssyklusen, men det er for ofte det første som skal kuttes når frister er nært forestående. Forhåpentligvis, etter å ha lest denne artikkelen, vil du sette pris på hvor nyttig det er å investere i testdrevet utvikling.
Hva er tankene dine om testdrevet utvikling? Er det noe du er interessert i å implementere, eller tror du det er sløsing med tid? Gi meg beskjed i kommentarene!