De laatste tijd horen en lezen we steeds meer over testgestuurde ontwikkeling. Dit domein wordt echter geleverd met een reeks uitdrukkingen en een specifiek jargon dat verwarrend kan zijn voor nieuwkomers. Dit artikel bevat de meest voorkomende definities, testtypen en testonderdelen. Use cases zullen worden verstrekt en, waar mogelijk, zal enige code in PHP ook worden gepresenteerd.
Een paar jaar geleden werd een nieuwe programmeur ingehuurd bij een ontwikkelingsteam. Zoals elke andere nieuwkomer was hij nogal in de war op zijn eerste dag. Terwijl hij luisterde naar de discussies rondom hem op kantoor, werden er heel wat testspecifieke termen gebruikt. Dit waren uitdrukkingen die onbekend waren voor onze fictieve nieuwe programmeur.
Gelukkig voor hem, omdat dit zijn eerste dag op het werk was, kregen de twee collega's later de opdracht om al dit jargon aan hem uit te leggen. Ze begonnen met een lijst met termen die betrekking hadden op de interne werking van een testcase.
Software testen software is praktisch een geautomatiseerde test. Testautomatisering bestaat al sinds vóór de pc; de eerste geautomatiseerde testkaders verschenen in de tijd van mainframes en consoles. Tegenwoordig is geautomatiseerd testen de aangewezen manier om te gaan. Waarom? Omdat testen een saaie en herhaalde taak is - iets wat niet echt geschikt is voor mensen. Geautomatiseerd testen is aanzienlijk sneller en nauwkeuriger dan handmatig testen. En nee, het elimineert niet de menselijke tester of een QA-team van de regeling. Het zorgt er simpelweg voor dat ze een meer voor mensen geschikte baan doen en hen in staat stellen het goed te doen.
Elke test moet breekbaar zijn in vier delen:
We ontwerpen elke test om vier verschillende fasen te hebben die achtereenvolgens worden uitgevoerd: de opstelling van de fixture, de oefening SUT, de resultaatverificatie en de demontage van de fixture. - xUnit Test Patterns: Refactoring Test Code, door Gerard Meszaros
Een armatuur vertegenwoordigt alle informatie die de test nodig heeft om te worden uitgeoefend. Een armatuur kan zo simpel zijn als het maken van een gewoon object, zoals $ testedObject = new RealObject ();, of iets zo ingewikkeld als het vullen van databases en het starten van gebruikersinterfaces.
Alles wat een te testen systeem (SUT) nodig heeft, zodat we de SUT kunnen gebruiken om zijn gedrag te verifiëren. - xUnit Test Patterns: Refactoring Test Code door Gerard Meszaros
U hebt deze terugkerende term waarschijnlijk waargenomen. Programmeurs noemen dit meestal SUT. Het vertegenwoordigt alle dingen die moeten worden getest. Afhankelijk van het type test (zie hieronder voor testtypes) kan de SUT veel dingen zijn, van een methode of een klasse tot het hele systeem.
Wat we ook testen. De SUT wordt altijd gedefinieerd vanuit het perspectief van de test. - xUnit Test Patterns: Refactoring Test Code, door Gerard Meszaros
Vanaf zijn tweede dag op het werk schreef onze programmeur zijn eerste test. Het was moeilijker dan hij had verwacht. Om het te schrijven, had hij een testkader, en hij moest een maken testcase en voer dan alle testmethoden. Er waren ook een handvol vreemde afhankelijkheden die hij moest uitzoeken. Het leek erop dat daarover leren DOC lag op schema.
Een testraamwerk is een applicatie die specifiek is ontworpen voor het testen van code in een specifieke taal. Het concept van a test kader werd gepionierd door Kent Beck in de vroege jaren '90. Zijn werk leidde later tot een raamwerk voor SmallTalk, SmalltalkUnit genaamd, en naderhand hernoemd naar Sunit.
Smalltalk heeft geleden omdat het een testcultuur ontbeerde. Deze kolom beschrijft een eenvoudige teststrategie en een kader om dit te ondersteunen. De teststrategie en -raamwerk zijn niet bedoeld als complete oplossingen, maar eerder als een startpunt van waaruit industriële krachtinstrumenten en -procedures kunnen worden geconstrueerd. - Simple Smalltalk Testing: With Patterns, door Kent Beck
Het was de eerste xUnit kader en definieerde het basisconcept van testen en de hierboven gepresenteerde voorwaarden. Tegenwoordig biedt bijna elke programmeertaal zijn versie van dit framework: PHPUnit voor PHP, JUnit voor Java, ShUnit voor UNIX Shell Scripts enzovoort. Je zou verbaasd zijn om te weten hoeveel dingen vandaag kunnen worden getest, en hoeveel tests kunnen worden geautomatiseerd.
Oorspronkelijk was een "testcase" gedefinieerd als de kleinste testeenheid van Kent Beck.
Wanneer je met een tester praat, is de kleinste testeenheid waar ze het over hebben een testcase. TestCase is een gebruikersobject en vertegenwoordigt een enkele testcase. - Simple Smalltalk Testing: With Patterns van Kent Beck
Deze dagen gebruiken we test methode om dit kleinste onderdeel te definiëren en een testcase verwijst meestal naar een reeks verwante testmethoden. Een typische situatie is bijvoorbeeld wanneer we onze code testen en een testcase verwijst naar de totaliteit van de testmethoden die een bepaalde klasse testen of wat dan ook de kleinste eenheid in onze programmeertaal is. Een testcase, vaak genoemd, wordt eenvoudigweg aangeduid als: "een toets."
Een testmethode is het kleinste deel van een testarchitectuur. Een testmethode is de eenheid die bestaat uit de hierboven gedefinieerde onderdelen: instellen / oefenen / verifiëren / laten vallen. Het is het essentiële onderdeel van elke test; degene die doet het werk.
Een testmethode is een definitieve procedure die een testresultaat oplevert. - Handleiding voor formulieren en stijlen, ASTM, 2012
Dit was gemakkelijk een van de meest verwarrende nieuwe termen voor onze nieuwe programmeur. Het vertegenwoordigt alle andere klassen en systeemcomponenten die onze SUT nodig heeft om correct te kunnen worden uitgevoerd. Maar ook moet de DOC specifieke methoden bieden waarmee we deze kunnen observeren en testen. De concepten van spotachtig en test dubbel zijn sterk gerelateerd aan de DOC.
Een individuele klasse of een component met een grote korrel waarop het geteste systeem (SUT) afhankelijk is. De afhankelijkheid is meestal een van delegatie via methodeaanroepen. - xUnit Test Patterns: Refactoring Test Code, door Gerard Meszaros
Al snel na het schrijven van zijn eerste paar tests, realiseerde de nieuwe kerel zich dat hij verschillende logische delen van de applicatie testte. Soms is het het beste om een klein deel geïsoleerd te testen; andere keren is het nodig om een groep objecten samen te testen en de manier waarop ze met elkaar praten; en andere keren moet je het hele systeem testen. Dingen zagen er ingewikkelder uit dan eerder werd verondersteld; dus onze programmeur ging verder en las een boek, en nog een, en nog een, en uiteindelijk begreep hij het.
De testpiramide is voor het eerst gedefinieerd in het boek, Slagen met Agile Software Development met behulp van Scrum, door Mike Cohn, en vervolgens snel overgenomen door de softwaregemeenschap.
De piramide vertegenwoordigt de drie belangrijkste testlagen: UI, Service en Eenheid.
De UI-laag staat voor het hoogste testniveau: wanneer het systeem wordt uitgeoefend via de gebruikersinterface en de hele applicatie als één wordt getest. Deze laag zou de kleinste hoeveelheid moeten zijn in onze vele tests.
De Servicelaag bevat verschillende testtypen. Het houdt zich voornamelijk bezig met de interne communicatie van modules en met de juiste werking van de externe API (application programming interface) van een applicatie. Er zouden verschillende van dergelijke tests in onze suites moeten zijn, maar ze mogen geen basis zijn voor onze tests. Deze tests zijn meestal het trainen van verschillende delen van de applicatie, en dus zijn ze redelijk traag. Ze moeten zo vaak mogelijk worden uitgevoerd, maar niet bij elke code die wordt opgeslagen. Waarschijnlijk bij elke build van het systeem of als er een commit gebeurt met het versiebeheer-systeem.
De Eenheidslaag verwijst naar tests die de kleinst mogelijke eenheden van onze code in volledige isolatie uitvoeren. Deze tests moeten de overgrote meerderheid van de tests vertegenwoordigen. Ze moeten erg snel zijn (1-4 milliseconden / test) en moeten zo vaak mogelijk worden uitgevoerd. Testgestuurde ontwikkeling (TDD) is een goed voorbeeld van hoe het gebruik van eenheidstests te maximaliseren.
Op basis van het bovenstaande voorbeeld bedacht de community verschillende gedetailleerdere versies van de testpiramide. Degene die ik als de beste beschouw, is te zien in de afbeelding hieronder.
De drie hoofdlagen kunnen duidelijk worden onderscheiden, maar de middenlaag is gedetailleerder. Naarmate de tijd verstreek, ontdekte en definieerde de softwarecommunity verschillende nieuwe testmethoden. Sommigen van hen waren opgenomen in de piramide.
Houd er rekening mee dat: geautomatiseerde testtechnieken en frameworks veranderen nog steeds erg snel. Dit is waarom, zoals je hieronder kunt zien, sommige uitdrukkingen nog niet duidelijk zijn en er verschillende termen zijn voor dezelfde definities, afhankelijk van de gemeenschap die ze heeft gepromoot.
Een unit-test vertegenwoordigt het testen van de kleinste eenheid die de programmeertaal toestaat. In objectgeoriënteerd programmeren zijn dit klassen / objecten. In andere talen kunnen het kleine modules zijn of zelfs functies / procedures.
EEN test in deze definities verwijzen naar hetzelfde als een testcase vertegenwoordigt.
Een test die het gedrag van een klein deel van het totale systeem verifieert. Wat een test omzet in een unit-test is dat het geteste systeem (SUT) een zeer kleine subset is van het totale systeem en mogelijk onherkenbaar is voor iemand die niet betrokken is bij het bouwen van de software. - xUnit Test Patterns: Refactoring Test Code door Gerard Meszaros
Unit tests vertegenwoordigen de overgrote meerderheid van de tests die een programmeur schrijft. Ja, het is waar: eenheidstests worden meestal geschreven door programmeurs. Eenheidstest helpt de programmeurs om de applicatie te ontwikkelen, veel voorkomende bugs, typefouten en regressies te voorkomen. Het zijn tests gemaakt door programmeurs voor programmeurs.
Dit is de reden waarom unit tests meer technisch en meer cryptisch van aard zijn. Ze zijn er om programmeurs te helpen betere code te schrijven; wanneer iets faalt op een unit-testniveau, is het meestal een probleem voor een programmeur om dit op te lossen.
Zoals de naam al doet vermoeden, worden componenttests geschreven voor iets grotere brokken van de toepassing. Een componententest oefent meestal een hele module of een groep logisch onderling afhankelijke eenheden uit.
Het onderdeel is een gevolg van een of meer ontwerpbeslissingen, hoewel het gedrag ook terug te voeren is op een bepaald aspect van de vereisten. - xUnit Test Patterns: Refactoring Test Code door Gerard Meszaros
Zeker, een componententest oefent meer code uit dan een eenheidscontrole. Het kan ook testen hoe sommige eenheden samenwerken en met elkaar praten.
Een component kan ook worden teruggevoerd op een vereiste of een deel van een vereiste. Dit betekent dat een componenttest niet alleen voor programmeurs is. Teamleiders, scrum-meesters, architecten en andere technisch betrokken mensen zijn zeker geïnteresseerd in de modules, door hun organisatie en soms zelfs door hun innerlijke werking. Deze mensen zijn niet noodzakelijk bekend met een specifieke programmeertaal. De test moet zich meer op het gedrag concentreren en de verwachtingen op een meer begrijpelijke manier definiëren.
Een eenheidstest kan bijvoorbeeld een foutmelding bevatten waarin staat dat:
TestFileAccessCanWriteToAFile: mislukt met beweren dat bestand '/ tmp / testbestand' aanwezig is op het systeem.
Zo'n bericht zou niet nuttig zijn voor een architect, een manager of een teamleider. Een componenttest kan mislukken met een meer beschrijvende fout:
Account Administration Test: Mislukt toen we probeerden 0 (nul) op te geven als het totale geld dat een gebruiker in zijn account heeft.
Zo'n test oefent een hogere functionaliteit uit. Op basis van het bovenstaande foutbericht kunnen er verschillende communicatielagen zijn en kunnen klassen / objecten betrokken zijn bij de bewerking van het opgeven van een bedrag als het totaal in iemands account.
Dit type test neemt verschillende modules in beslag en controleert hoe deze met elkaar worden geïntegreerd. Hiermee wordt gecontroleerd of de interne module-API's compatibel zijn en werken zoals verwacht.
De term laat echter een breed scala van mogelijke toepassingen toe. Sommige softwaregemeenschappen houden nauw verband met integratietests en testen hoe onze applicatie werkt binnen het medium dat moet worden uitgevoerd. Met andere woorden, hoe het integreert in het hogere systeem.
Anderen definiëren de integratietest op verschillende niveaus: alles wat de communicatie tussen twee elementen definieert, kan worden gezien als een integratie. Deze elementen kunnen eenheden zijn, zoals klassen, modules of zelfs hogere functionele delen van de software.
Er is geen unaniem geaccepteerde definitie voor de term integratietest.
De GUI van een toepassing spreekt met de software door de API van de software. Testen op dit niveau oefent veel code uit en kan relatief veel tijd verliezen.
API is het middel waarmee andere software een deel van de functionaliteit kan oproepen. - xUnit Test Patterns: Refactoring Test Code door Gerard Meszaros
In objectgeoriënteerd programmeren worden dergelijke API's gedefinieerd door de openbare methoden van de klassen. Als we echter een architectonisch ontwerpschema op hoog niveau bekijken, kan de betekenis van de API worden beperkt tot de openbare methoden van de klassen die functionaliteit bieden via de grenzen van de bedrijfslogica. Deze grensklassen vertegenwoordigen de API en we moeten testen of het systeem zich gedraagt zoals verwacht als het wordt aangeroepen en gebruikt.
Meestal worden deze tests periodiek uitgevoerd en duurt het lang voordat ze zijn voltooid.
Er zouden slechts enkele zeldzame gevallen moeten zijn wanneer u een test wilt laten uitvoeren op de presentatie van een applicatie. Er zit echt geen logica in de GUI-laag, alleen presentatie.
Testen of een knop groen of rood is, of heeft 30px
in de breedte is nutteloos, en is te veel van een overhead. Dus spring niet in het testen van uw meningen. Als er iets vreselijk mis gaat met de grafische gebruikersinterface, zal dit worden opgemerkt in de verkennende handmatige testfase.
Het testen van weergaven zou slechts twee dingen moeten doen: test voorwaardelijke presentatie en test of de verwachte API wordt aangeroepen.
Het is verleidelijk om te beginnen met het testen van uw mening. Niet doen! Test alleen wat volgens jou kan mislukken. Test alleen voor waarden of functie-aanroepen. Controleer nooit op GUI-elementen of hun eigenschappen. Gebruik REGEX waar mogelijk om strings te matchen en trefwoorden aan te vinken die waarschijnlijk niet zullen veranderen.
De volgende pseudo-code is bijvoorbeeld een slecht voorbeeld voor het testen van de aanwezigheid van een tekenreeks op het scherm.
function testItCanTellTheNameOfTheUser () // wat rendering code logica hier $ renderedName = $ this-> renderName (); $ this-> assertEquals ('Gebruiker heeft de naam'. $ renderedName ['first']. ". $ renderedName ['last']. '.');
Deze test is niet alleen moeilijk te lezen, maar hij test ook op een exacte zin - zoiets als "Gebruiker heeft de naam John Doe.", inclusief interpunctie! Waarom is dit slecht? Omdat iemand gemakkelijk de vorm van deze zin kan veranderen zonder de betekenis ervan te veranderen.
Wat als onze klant vereist Achternaam voornaam formulier te presenteren? Dat zou onze test mislukken. We moeten ons afvragen: zou de test falen? Hebben we de softwarelogica gewijzigd? Ik zeg nee, het moet niet falen. De naam zou nog steeds op het scherm aanwezig zijn; de volgorde van de twee delen zou gewoon anders zijn. Dit is een meer geschikte test.
function testItCanTellTheNameOfTheUser () // wat rendering code logica hier $ renderedName = $ this-> renderName (); $ this-> assertRegExp ($ renderedName ['first'], $ renderedName); $ this-> assertRegExp ($ renderedName ['last'], $ renderedName);
Dit zorgt er nu voor dat de naam aanwezig is, maar het maakt niet uit van het lexicale construct. Iemand zou de eerste zin in iets kunnen veranderen, zoals Don, John is de naam van de huidige gebruiker. De betekenis zal hetzelfde blijven en de test zal nog steeds correct verlopen!
Na een maand of zo te hebben gewerkt, realiseert onze fictieve nieuwe programmeur zich dat, zelfs als de piramide best cool is, hij niet compleet is. Soms zijn er een paar of zo verschillende tests die moeten worden uitgevoerd - en ze zijn vrij moeilijk te plaatsen op de piramide.
Dit zijn een van de meest controversiële tests. Afhankelijk van het soort boeken dat u aan het lezen bent, kunnen acceptatietests worden aangeduid als Functionele testen
of
of
of
Elke naam is afkomstig van een andere community of auteur. Ik persoonlijk Acceptatietests of End-to-end-tests.
Een acceptatietest verifieert het gedrag van een deel van de zichtbare functionaliteit van het totale systeem. - xUnit Test Patterns: Refactoring Test Code door Gerard Meszaros
Zo'n test zal iets doen op de GUI. De verandering zal in het hele systeem gebeuren. Gegevens worden opgeslagen in de database of het bestandssysteem. Netwerkcommunicatie zal worden gemaakt. Ten slotte wordt de grafische gebruikersinterface gecontroleerd op de reactie van het systeem. Dergelijke tests proberen een gebruiker volledig na te bootsen.
Acceptatietests zijn nauw gerelateerd aan de belanghebbenden van onze applicatie. Ze worden meestal gedefinieerd in de taal van het bedrijf en als er iets misgaat, wordt een hele functionaliteit als niet meer actueel beschouwd. Deze tests worden ook gebruikt om de functionaliteit op hoog niveau van de toepassing te definiëren.
Meestal zijn ze geschreven door QA en management en geïmplementeerd door programmeurs. Oorspronkelijk werden ze uitgevonden als een brug tussen management en productie. In sommige situaties zijn ze geslaagd. De taal van de tests is flexibel genoeg om te worden geschreven en begrepen door mensen die niet direct betrokken zijn bij het schrijven van software.
Er zijn speciale raamwerken voor dergelijke tests, zoals Fitness, Selenium, Watir, Cucumber en anderen.
Dit is een meer speciaal geval en wordt niet al te vaak gebruikt. Je kunt ze soms gebruiken in object-georiënteerde talen als interfaces en overerving getest moeten worden. De test zorgt er feitelijk voor dat een klasse echt alle interfaces implementeert die het heeft.
Contracttests leggen uit hoe een klasse een superklasse moet uitbreiden of een interface moet implementeren. - J. B. Rainsberger
In sommige toepassingen is de term contract wordt gebruikt voor een ander type test. Deze tweede definitie van de contracttest controleert of het contract tussen onze applicatie en een externe component waarvan we afhankelijk zijn, wordt gerespecteerd. Deze tests oefenen de huidige code en code van derden uit en zorgen ervoor dat de resultaten zijn zoals verwacht.
Na een welverdiende vakantie is onze niet-zo-junior programmeur weer aan het werk. Het was zijn eerste verlof en hij voelt zich vervuld van nieuwe kracht voor het schrijven van tests en code. Na zes maanden voelt hij zich vrij goed op zijn werk; hij heeft zich goed geïntegreerd in het team en hij schrijft echt goede code. Maar van tijd tot tijd heeft hij een frustrerend gevoel. Het is saai en foutgevoelig om elke avond vijf verschillende soorten testsuites in een strikt gedefinieerde volgorde uit te voeren.
Dan is er nog een vreemde discussie tussen zijn teamleider en het management. Ze praten over C.I.. en CD.. Wat zou dat kunnen betekenen? Het was te cryptisch om onze nieuwe programmeur te begrijpen. Een paar weken later was er een bedrijfsbrede boodschap: "Voer alstublieft uw avondproeven niet meer uit. Wij hebben C.I.!. Om meer te weten te komen, ging hij naar zijn teamleider en vroeg: "Wat is CI en CD?".
Teams die sterk afhankelijk zijn van geautomatiseerd testen, hebben een manier nodig om al deze tests op een georganiseerde en efficiënte manier uit te voeren. Een doorlopend integratiesysteem helpt hierbij.
Continuous Integration is een software-ontwikkelingspraktijk waarbij leden van een team hun werk vaak integreren, meestal integreert elke persoon zich minstens dagelijks - wat leidt tot meerdere integraties per dag. Elke integratie wordt geverifieerd door een geautomatiseerde build (inclusief test) om integratiefouten zo snel mogelijk te detecteren. - Martin Fowler
Op basis van deze definitie kan het continue integratieproces onze tests uitvoeren zonder menselijke tussenkomst. In de definitie wordt frequente integratie dagelijks als voorbeeld gegeven, maar ik kan je vertellen dat het echt gaaf is om te werken aan een softwarebasis die automatisch wordt getest op elke commit. Veelvuldig committeren betekent dat elke aanpassing die voltooid is moet worden vastgelegd, zodat je tientallen commits kunt hebben op één dag. Elke commit activeert een complete test van het systeem en u krijgt een mooie e-mail, groen of rood, afhankelijk van het resultaat, in slechts een paar minuten. Als de mail groen is, is het product in theorie onmiddellijk verzendbaar.
Dit is niet zo gerelateerd aan testen, maar aan CI. Terwijl CI u een afleverbaar systeem toestaat, worden releases nog steeds periodiek en handmatig uitgevoerd.
Continuous Delivery automatiseert alle stappen van code naar client.
Nadat alles op CI-niveau is gedaan, gaat doorlopende levering nog een stap verder en worden de software-installatiekits gebouwd, worden deze indien nodig gepubliceerd en kan het zelfs externe updateprocedures voor clients activeren. Het doel van een dergelijk systeem is om het product zo snel mogelijk aan de eindgebruiker te leveren. Het is sterk afhankelijk van de geautomatiseerde tests en als ze allemaal worden doorgegeven, wordt het product geleverd. Periode.
Zelfs als dit in sommige situaties erg aantrekkelijk klinkt, is het in de meeste toepassingen nog steeds te gevaarlijk. Gewoonlijk moet elk fatsoenlijk kritisch systeem onder een verkennende handmatige testsessie vóór levering worden ondergebracht.
Er zijn delen van een testprocedure die eenvoudigweg te moeilijk - zo niet onmogelijk - te automatiseren zijn. Dat is waarom een Verkennend handboek Testen sessie wordt meestal gedaan vóór elke softwareversie. Deze tests kunnen worden uitgevoerd door gespecialiseerde testers of door de programmeurs, afhankelijk van de structuur van het team en het bedrijf.
Handmatig testen omvat verbeeldingskracht. Mensen snuffelen rond het systeem en zorgen ervoor dat het werkt en eruit ziet zoals gewenst.
Sommige teams overwegen handmatig testen a << Break it if you can! >> concept.
Je kunt het testen van jargon niet vermijden. Hopelijk heeft dit artikel enig licht geworpen op de verschillen tussen de verschillende testvormen. Nog vragen? Vraag hieronder!