Het testen van je code is vervelend, maar de impact van het niet doen van deze code kan orden van grootte hinderlijker zijn! In dit artikel gebruiken we testgestuurde ontwikkeling om onze code effectiever te schrijven en te testen.
Sinds het begin van het computertijdperk hebben programmeurs en bugs gestreden voor suprematie. Het is een onvermijdelijke gebeurtenis. Zelfs de grootste programmeurs vallen ten prooi aan deze anomalieën. Geen code is veilig. Dat is waarom we testen. Programmeurs, in ieder geval verstandige, testen hun code door deze op ontwikkelmachines uit te voeren om er zeker van te zijn dat het doet wat het zou moeten doen.
Test gedreven ontwikkeling is een programmeertechniek waarbij u tegelijkertijd code en geautomatiseerde testcode moet schrijven. Dit zorgt ervoor dat u uw code test - en stelt u in staat om uw code snel en gemakkelijk opnieuw te testen, omdat deze automatisch is.
Testgestuurde ontwikkeling, of TDD zoals we dat vanaf nu noemen, draait om een korte iteratieve ontwikkelingscyclus die ongeveer als volgt verloopt:
Heb je ooit een programma met opzet overgeslagen omdat:
Meestal gebeurt er niets en kunt u uw code probleemloos naar productie verplaatsen. Maar soms, als je eenmaal bent verhuisd naar de productie, gaat het mis. Je bent vast aan het repareren van honderd gaten in een zinkend schip, met meer elke minuut. Je doet niet wil je jezelf in deze situatie bevinden.
TDD was bedoeld om onze excuses te elimineren. Wanneer een programma is ontwikkeld met behulp van TDD, kunnen we wijzigingen aanbrengen en dit snel en efficiënt testen. Het enige wat we moeten doen is de geautomatiseerde tests uitvoeren en voila! Als het alle geautomatiseerde tests doorstaat, dan zijn we goed om te gaan - zo niet, dan betekent dit gewoon dat we iets hebben gebroken met de veranderingen. Door te weten welke exacte delen van de test zijn mislukt, kunnen we ook gemakkelijk vaststellen welk deel van de wijzigingen is verbroken, zodat het eenvoudiger wordt om de bugs te verhelpen.
Er is een groot aantal PHP-geautomatiseerde testraamwerken die we kunnen gebruiken. Een van de meest gebruikte testkaders is PHPUnit.
PHPUnit is een geweldig testraamwerk dat eenvoudig kan worden geïntegreerd in uw eigen projecten of andere projecten die bovenop populaire PHP-frameworks worden gebouwd.
Voor onze doeleinden hebben we echter niet de vele functies nodig die PHPUnit biedt. In plaats daarvan kiezen we ervoor om onze tests te maken met behulp van een veel eenvoudiger testraamwerk, genaamd SimpleTest.
Laten we in de volgende stappen aannemen dat we een gastenboektoepassing ontwikkelen waarin elke gebruiker gastenboekitems kan toevoegen en bekijken. Laten we aannemen dat de markup is voltooid en dat we gewoon een klasse maken die de applicatielogica van het gastenboek, waar de applicatie wordt ingevoegd en gelezen naar de database. Het leesgedeelte van deze klas is wat we gaan ontwikkelen en testen.
Dit is misschien wel de gemakkelijkste stap van allemaal. Zelfs deze man zou het kunnen doen:
Download SimpleTest hier en pak het uit naar een map naar keuze - bij voorkeur de map waar u uw code gaat ontwikkelen, of uw PHP include_path voor eenvoudige toegang.
Voor deze zelfstudie heb ik de map zo ingesteld:
Index.php voert guestbook.php uit, roept de weergavemethode aan en geeft de vermeldingen weer. In de klassenmap plaatsen we de guestbook.php-klasse en in de testmap plaatsen we de eenvoudigste bibliotheek.
De tweede stap, die eigenlijk de belangrijkste is, is om te beginnen met het maken van uw tests. Daarvoor moet je echt plannen en nadenken over wat je functie gaat doen, welke mogelijke invoer het krijgt en de bijbehorende uitgangen die het zal verzenden. Deze stap lijkt op het spelen van een schaakspel - je moet alles weten over je tegenstander (het programma), inclusief al zijn zwakke punten (mogelijke fouten) en sterke punten (wat gebeurt er als het met succes wordt uitgevoerd).
Dus voor onze gastenboektoepassing, laten we de schema's vastleggen:
Array ([0] => Array (['name'] = "Bob" ['message'] = "Hallo, ik ben Bob.") [1] => Array (['name'] = "Tom" ['message'] = "Hallo, ik ben Tom."))
Nu kunnen we onze eerste test schrijven. Laten we beginnen met het creëren van een bestand met de naam guestbook_test.php in de testmap.
Laten we vervolgens converteren wat we hebben vastgesteld vanaf stap twee,.
add ("Bob", "Hallo, ik ben Bob."); $ guestbook-> add ("Tom", "Hallo, ik ben Tom."); $ entries = $ guestbook-> viewAll (); $ count_is_greater_than_zero = (tel ($ entries)> 0); $ This-> assertTrue ($ count_is_greater_than_zero); $ this-> assertIsA ($ entries, 'array'); foreach ($ entries as $ entry) $ this-> assertIsA ($ entry, 'array'); $ This-> assertTrue (isset ($ binnenkomst [ 'naam'])); $ This-> assertTrue (isset ($ binnenkomst [ 'boodschap'])); function testViewGuestbookWithNoEntries () $ guestbook = new Guestbook (); $ Guestbook-> Verwijder (); // Verwijder eerst alle vermeldingen zodat we weten dat het een lege tabel is $ entries = $ guestbook-> viewAll (); $ this-> assertEqual ($ entries, array ());Beweringen zorgen ervoor dat een bepaald ding is wat het hoort te zijn - eigenlijk zorgt het ervoor dat wat wordt teruggegeven, is wat je verwacht dat het terugkeert. Als een functie bijvoorbeeld de waarde true moet teruggeven als deze is geslaagd, moeten we dat in onze test doen beweren dat de retourwaarde gelijk is aan true.
Zoals je hier kunt zien, testen we de weergave van het gastenboek met items en zonder. We controleren of deze twee scenario's voldoen aan onze criteria van stap twee. U hebt waarschijnlijk ook opgemerkt dat elk van onze testfuncties begint met het woord 'testen'. We hebben dit gedaan omdat, wanneer SimpleTest deze klasse uitvoert, het alle functies zal zoeken die beginnen met het woord 'testen' en het uitvoeren.
In onze testklasse hebben we ook een aantal assertiemethoden gebruikt, zoals assertTrue, assertIsA en assertEquals. De functie assertTrue controleert of een waarde waar is. AssertIsA controleert of een variabele van een bepaald type of klasse is. En ten slotte, assertEquals controleert of een variabele volledig gelijk is aan een bepaalde waarde.
Er zijn andere assertiemethoden die worden aangeboden door SimpleTest, die zijn:
assertTrue ($ x) | Mislukt als $ x false is |
assertFalse ($ x) | Mislukt als $ x waar is |
assertNull ($ x) | Mislukt als $ x is ingesteld |
assertNotNull ($ x) | Mislukt als $ x niet is ingesteld |
assertIsA ($ x, $ t) | Mislukt als $ x niet de klasse of het type $ t is |
assertNotA ($ x, $ t) | Mislukt als $ x van de klasse is of typ $ t |
assertEqual ($ x, $ y) | Mislukt als $ x == $ y onwaar is |
assertNotEqual ($ x, $ y) | Mislukt als $ x == $ y waar is |
assertWithinMargin ($ x, $ y, $ m) | Fail als abs ($ x - $ y) < $m is false |
assertOutsideMargin ($ x, $ y, $ m) | Fail als abs ($ x - $ y) < $m is true |
assertIdentical ($ x, $ y) | Mislukt als $ x == $ y fout is of als het type niet overeenkomt |
assertNotIdentical ($ x, $ y) | Mislukt als $ x == $ y waar is en typen overeenkomen |
assertReference ($ x, $ y) | Fail tenzij $ x en $ y dezelfde variabele zijn |
assertClone ($ x, $ y) | Mislukt tenzij $ x en $ y identieke exemplaren zijn |
assertPattern ($ p, $ x) | Fail tenzij de regex $ p overeenkomt met $ x |
assertNoPattern ($ p, $ x) | Mislukt als de regex $ p overeenkomt met $ x |
expectError ($ x) | Slikt eventuele aankomende overeenkomende fouten door |
beweren ($ e) | Mislukt op mislukt verwachtingsobject $ e |
Assertiemethode met dank aan http://www.simpletest.org/en/unit_test_documentation.html
Als u klaar bent met het schrijven van de code, moet u de test uitvoeren. De eerste keer dat u de test uitvoert, is het ZOU FOUTEN. Als dat niet het geval is, betekent dit dat uw test niet echt iets test.
Om uw test uit te voeren, gewoon uitvoeren guestbook_test.php in uw browser. Dit zou je eerst moeten zien:
Dit is gebeurd omdat we onze gastenboekklasse nog niet hebben gemaakt. Hiertoe maakt u guestbook.php in uw klassenmap. De klasse moet de methoden bevatten die we van plan zijn te gebruiken, maar mag in eerste instantie niets bevatten. Vergeet niet dat we eerst de tests schrijven voor het schrijven van elke code.
Wanneer u de test opnieuw uitvoert, ziet deze er ongeveer zo uit:
Zoals we hier kunnen zien, is onze test nu aan het winnen door te falen. Dit betekent dat onze test nu klaar is om 'beantwoord' te worden.
Afbeelding met dank aan http://www.gamercastnetwork.com/forums
Stap 5. Beantwoord uw test door code te schrijven
Op een gegeven moment voelen we ons allemaal zo wanneer we programmeren.
Afbeelding met dank aan http://fermentation.typepad.com/fermentationNu we een werkende geautomatiseerde test hebben, kunnen we beginnen met het schrijven van code. Open je guestbook.php klasse en begin met het maken van het antwoord op uw test.
'Kirk', 'bericht' => 'Hallo, ik ben Kirk.' ), array ('name' => 'Ted', 'message' => 'Hallo, ik ben Ted.')); public function viewAll () // Hier moeten we alle records uit de database ophalen. // Dit wordt gesimuleerd door de $ _entries array return self :: $ _ entries te retourneren; public function add ($ name, $ message) // Hier simuleren we insertie in de database door een nieuw record toe te voegen aan de array $ _entries // Dit is de juiste manier om het te doen: self :: $ _ entries [] = array ('naam' => $ naam, 'bericht' => $ bericht); self :: $ _ entries [] = array ('notname' => $ name, 'notmessage' => $ message); // oeps, er is hier ergens een bug die waar is; public function deleteAll () // We hebben zojuist de array $ _entries ingesteld om zelf te simuleren :: $ _ entries = array (); geef waar terug;Deze guestbook.php-klasse bevat expres bepaalde bugs, zodat we kunnen zien hoe het eruit ziet als onze test mislukt.
Zodra we onze test hebben uitgevoerd, zouden we zoiets als dit moeten zien:
De testoutput laat ons zien in welke test en in welke bewering onze code faalde. Hieruit kunnen we eenvoudig vaststellen dat regel 16 en 17 de bewering waren die de fout gooide.
assertTrue (isset ($ binnenkomst [ 'naam'])); $ This-> assertTrue (isset ($ binnenkomst [ 'boodschap'])) ;?Dit vertelt ons duidelijk dat de geretourneerde entry-array niet de juiste array-sleutel had. Op basis hiervan zullen we gemakkelijk weten welk deel van onze code fout is gegaan.
$ naam, 'bericht' => $ bericht); // opgelost! geef waar terug; ?Nu, als we onze test opnieuw uitvoeren, moet dit ons laten zien:
Stap 6. Refactoreer en verfijn uw code
Afbeeldingen met dank aan http://www.osborneink.com en http://phuketnews.phuketindex.comOmdat de code die we hier testen vrij eenvoudig is, duurde het testen en repareren van bugs niet lang. Maar als dit een complexere toepassing was, zou u uw code meerdere keren moeten wijzigen, zodat deze schoner moet worden, zodat deze eenvoudiger te onderhouden is en nog veel meer. Het probleem hiermee is echter dat verandering meestal extra bugs introduceert. Hier komt onze geautomatiseerde test binnen - als we eenmaal wijzigingen hebben aangebracht, kunnen we de test gewoon opnieuw uitvoeren. Als het nog steeds slaagt, betekent dit dat we niets hebben gebroken. Als het mislukt, weten we dat we een fout hebben gemaakt. Het informeert ons ook waar het probleem ligt en, hopelijk, hoe we het kunnen oplossen.
Stap 7. Spoelen en herhalen
Afbeelding met dank aan http://www.philstockworld.comUiteindelijk, wanneer uw programma nieuwe functionaliteit vereist, moet u nieuwe tests schrijven. Dat is eenvoudig! Spoel en herhaal de procedures vanaf stap twee (aangezien je SimpleTest-bestanden al zouden moeten zijn ingesteld) en begin de cyclus helemaal opnieuw.
Conclusie
Er zijn veel meer diepgaande testgestuurde ontwikkelingsartikelen die er zijn, en nog meer functionaliteit voor SimpleTest dan wat in dit artikel werd getoond, zaken zoals mock-objecten, stubs, die het gemakkelijker maken om tests te maken. Als je meer wilt lezen, zou de testgestuurde ontwikkelingspagina van Wikipedia je op het juiste pad moeten brengen. Als u graag SimpleTest gebruikt als testomgeving, bladert u door de online documentatie en bekijkt u de andere functies.
Testen is een integraal onderdeel van de ontwikkelingscyclus, maar het is al te vaak het eerste dat wordt onderbroken wanneer er deadlines zijn. Hopelijk, na het lezen van dit artikel, zult u waarderen hoe nuttig het is om te investeren in testgestuurde ontwikkeling.
Wat denk je over testgestuurde ontwikkeling? Is het iets dat je wilt implementeren, of denk je dat het tijdverspilling is? Laat het me weten in de comments!