Voorkom spaghetticode in je test automation project

Spaghetticodeinclusief quick start voor RestSharp v107 en hoger

Spaghetticode, de nachtmerrie van elke ontwikkelaar en testautomatiseerder. Hoe voorkom je dit in je Test Automation project? Hoe zorg je als testautomatiseerder ervoor dat je zelf niet de aanstichter wordt van spaghetticode? Hoe behoud je het overzicht en kun je dus beter instaan voor de gevolgen en kwaliteit van de testcode zelf? André zet een aantal handige inzichten voor je op een rij.

Structuur in repository

Alles begint met, zowel voor de beginnende als de meer ervaren testautomatiseerder onder ons, het opbouwen van een goed gestructureerde repository van je testproject. Of misschien wel voor de echte beginners bij het begrijpen van de opbouw van de folderstructuur van zo’n repository. Zo weet ik van sommige beginnende test(automatiseerd)ers dat zo’n boomstructuur in je IDE (Integrated Development Environment) wat overweldigend kan overkomen. Zeker als het project al even bestaat en uitgegroeid is tot vele folders en subfolders. Al snel steken dan diverse vragen de kop op, als waar kan ik wat vinden?

Hieronder inzicht in een structuur die goed kan helpen bij een Specflow project voor het testen van REST API’s met de RestSharp Library en wat kleine uitstapjes naar Selenium, inclusief API helpers. Dit slechts ter illustratie, want uiteraard zijn de basisprincipes toepasbaar op vele andere testprojecten, die gebruik maken van andere technologieën en/of tools.

Afsluitend zoom ik nog even specifiek in op de RestSharp library, omdat deze redelijk recent (februari 2022) een upgrade kreeg naar v107. Hierin zitten nogal wat breaking changes ten opzichte van v106 en eerdere versies.

Projectstructuur

Een goede basisstructuur zijn de folders zoals hieronder getoond. Hoewel de Visual Studio IDE de folders hier alfabetisch toont, licht ik ze in deze blog toe in de volgorde van de meer op de business gerichte laag, naar de meer technische code laag. De daadwerkelijke code, en dus deze projectstructuur, inclusief een dummy API is ook beschikbaar via de GitHub pagina van André.

Features

In de ‘Feature’ folder plaats je alle feature files. Het maakt geen verschil of je met Specflow of Cucumber werkt, het basisidee blijft hetzelfde. Je start vanuit een feature file. De feature files beschrijven in de Gherkin taal de op te leveren features inclusief de scenario’s die je wilt testen. Je beschrijft deze op business level in Jip en Janneke taal in het Engels, Of naar wens in het Nederlands. Houd hierbij de standaard opzet aan met Given, When, Then. Wil je je hierin nog meer verdiepen, lees dan mijn eerdere blog over Gherkin.

Denk bij het creëren van de feature structuur ook alvast na over de mogelijkheid tot het wel of niet parallel willen/kunnen runnen van je testen. Zo kun je de doorlooptijd verkorten en snelle feedback loops creëren. Als je testen niet slagen, wil je namelijk snel kunnen doorpakken en uitzoeken waarom iets fout gaat. Het mooiste is wanneer al je scenario’s onafhankelijk van elkaar kunnen draaien. Is dit echter door wat voor omstandigheden niet mogelijk? Zorg er dan in elk geval voor dat de diverse feature files niet van elkaar afhankelijk zijn of overlap hebben in het gebruik van dezelfde testdata/uitgangsposities. Zo kun je in elk geval wel meerdere feature files parallel runnen, maar blijven de scenario’s binnen die feature files wel serieel draaien. Dit alles uiteraard voor die enorm belangrijke doorlooptijd van je testen, die de grondbeginselen vormen voor een succesvol test automation framework!

Ik kan het niet vaak genoeg benadrukken. Niemand zit immers te wachten op een testframework dat uren nodig heeft voor het afwerken van zijn testen. Zo kunnen de testen de gehele build en release pipeline vertragen/ophouden, wat zowel bij de developers als PO’s tot de nodige irritaties kan leiden. Als wij als developers/testers te lang moeten wachten op de uitslagen, weten we allemaal dat we tussendoor ander werk oppakken. Het vaak switchen van context komt meestal niet ten goede aan de efficiëntie. Of nog erger, duurt het te lang, dan gaat men de testen negeren of omzeilen.

Steps

In de ‘Steps’ folder bevindt zich de ‘glue-code’, deze code koppelt de business-code in overzichtelijke herbruikbare blokken aan onderliggende meer technisch wordende methodes en helpers. Roep hier bijvoorbeeld binnen elke stap 1 of enkele API endpoints aan vanuit de action files. Gebruik hier eventueel ook de mogelijkheden voor het toeschrijven van waarden aan de context. Zo kun je deze waarden over meerdere stappen in zowel dezelfde steps file als andere steps files delen. Structureer deze step functionaliteit naar logische gegroepeerde functionaliteiten en stop dus niet alle step glue-code in 1 file. In het begin lijkt dat misschien nog handig, maar als het project snel groeit, wordt het al vlug lastig code terug te vinden. Terwijl dat terugvinden juist zo belangrijk is, want de kracht van Specflow en Cucumber zit immers in het opstellen van begrijpbare HERBRUIKBARE blokjes code.

Probeer dus al in een zo vroeg mogelijk stadium na te denken over een mogelijke structuur/opsplitsing, bijvoorbeeld naar (gegroepeerde) functionaliteit. Let op: dit betekent in mijn ogen dus niet altijd dat elke feature file 1 op 1 mapt met een bijbehorende step file. In veel gevallen zal dit zo zijn (zeker bij API testen waar endpoints in mijn ogen gegroepeerd kunnen/moeten worden getest), maar houdt er rekening mee dat je ook de steps wilt hergebruiken vanuit andere feature files. Denk hierbij bijvoorbeeld aan een aparte steps file voor alle herbruikbare login steps, die je veelal voor alle scenario’s/ feature files nodig hebt. Hergebruik bestaande steps waar mogelijk en vermijd zoveel mogelijk duplicate code. Dit alles ten behoeve van de overzichtelijkheid en onderhoudbaarheid. Vraag jezelf wel altijd af wat voor jouw project werkt en kijk altijd naar de context. Geen enkel project is hetzelfde en kan een net wat andere groepering of opsplitsing voor jou wel werken die voor een ander niet werkt.

Voor de onderhoudbaarheid en het volgen van de code door iedereen in het team, en wellicht zelfs door de PO en of analisten, is het handig ook de laag onder de Gherkin stappen leesbaar te houden. Een toepassing die dit vereenvoudigt is het gebruik van de Fluent Assertions Library voor C#, of iets vergelijkbaars voor de betreffende taal waarmee jij werkt. Zo heb je bijvoorbeeld ook de vergelijkbare Chai Assertions Library voor JavaScript. Overigens is het in alle gevallen goed je af te vragen wie nu, en mogelijk in de toekomst, de lezers van welke laag van de ‘(test)code’ zijn. Wanneer de testverantwoordelijkheid ligt bij een zeer technisch team en men niet voorziet dat dit gaat veranderen, kan je natuurlijk de kritische vraag stellen hoeveel tijd en energie je moet steken in het leesbaar maken van de steps voor de business.

Actions

Gebruik deze folder voor het overzichtelijk bij elkaar houden van al je API endpoints. Blijf in deze files ver weg van de business logica. Zo houd je ze schoon en overzichtelijk zonder toeters en bellen. Hierdoor zie je bijvoorbeeld snel of alle endpoints wel zijn geïmplementeerd en of je de endpoints überhaupt raakt met je testen. Op zijn minst verwacht je dat de ‘reference’ een getal hoger dan 0 heeft, zie ook onderstaande afbeeldingen ter illustratie.

Context

Voor het eenvoudig hergebruiken van values tussen verschillende steps uit verschillende step files schrijf je deze weg naar de scenariocontext. Variabele kun je zo hergebruiken over meerdere scenario’s zonder dat de values elkaar in de weg zitten. Natuurlijk wordt dit nog belangrijker of zelfs een ‘must’, wanneer scenario’s die dezelfde steps (her)gebruiken parallel runnen.

Helpers

Deze folder kan je gebruiken voor herbruikbare methodes. Bijvoorbeeld voor het vertalen van user id’s naar leesbare gebruikersnamen. Zo kan het voorkomen dat API’s enkel werken met Guid’s als input, die een specifieke user representeren. Gebruik hierbij alsjeblieft niet die Guid in je Gherkin/feature scenario descriptions, want dat komt niet ten goede aan het leesbaar maken van je scenario’s voor de business.

Ook kun je veel terugkerende acties die jij voor jouw specifieke API nodig hebt, kwijt in de helpers folder. In mijn geval maken wij bijvoorbeeld gebruik van authorization token methods als addToken en useBaseUrl. Handig als je meerdere applicaties met verschillende, maar wel bij elkaar behorende base urls en authorization rules hebt. In deze folder is ook ruimte voor Selenium API Helpers voor het snel klaarzetten van data/uitgangsposities. Aangezien helper methodes snel kunnen groeien, is het de moeite waard het gebruik van subfolders te overwegen. De helper methodes zijn dan ook weer te categoriseren.

Models

Voor het werken met data, zowel als input voor je testen als voor de output, moet je gebruik maken van modellen. Die modellen zijn nodig om de data van je scenario outline tabellen vanuit je Gherkin te mappen of te matchen naar de step files. Voor het opbouwen van Json body’s voor je POST API calls en voor het afvangen van de teruggegeven data vanuit vrijwel alle andere API calls als GET en PUT acties.

Maak duidelijk onderscheid in de namen voor modellen. Weet je vooraf dat je met heel veel API endpoints te maken gaat krijgen en heel veel datatabellen voor scenario outlines gaat gebruiken, splits deze dan ook op naar functionaliteit. Enerzijds voorkom je zo duplicatie en anderzijds vind je ze gemakkelijk terug voor wijzigingen of als je ze nodig hebt voor nieuwe stukjes code/steps.

Gratis tip voor de Specflow en C# gebruikers: heb je geen toegang tot de source code, dan hoef je de modellen niet helemaal zelf opnieuw uit te schrijven. Copy-paste de example json output uit je Swagger specs naar tools zoals  https://json2csharp.com/. De modellen worden dan automatisch voor je gegenereerd. Bij gebrek aan Swagger specs, kan uiteraard ook  de daadwerkelijke response worden gebruikt. Al dan niet verkregen via de debug mode in Visuals Studio of rechtstreeks uit Postman, net wat jij gemakkelijk vindt. Bij gebruik van de debug mode in C# kan https://jsonformatter.curiousconcept.com/ een mooie tussenstap zijn voor beter inzicht in de datastructuur. Let op! Ben je bij het gebruik van dit soort tools wel bewust van het feit dat je data in het wereldwijde web gooit, dus doe dit nooit met vertrouwelijke data!

Resources

Deze folder gebruik je voor test data files. Moet je bijvoorbeeld een dummy document meesturen met een multipart rest call? Of zit er nog 1 zo’n irritante (legacy) soap call tussen? Dan kan je deze ook gebruiken voor bijvoorbeeld xml files. Goed om te weten dat als het echt moet, je RestSharp eventueel ook kan mis-/gebruiken voor Soap calls, door ’xml’s bij te sluiten als body.

Pages

Tot zover is bovengenoemde structuur gericht op API testing. Ook als we even inzoomen op de veel voorkomende UI projecten, is bovenstaande structuur aan te vullen met o.a. een folder Pages en API/wait helpers. Waarbij Helpers dus allesomvattend kunnen zijn. Zie ook hierboven de eerder aangehaalde helpers folder. De Pages folder kan dan ingezet voor het gebruik van Page Object Models. Houd ook hier de onderhoudbaarheid in gedachte. Veel websites zijn tegenwoordig opgezet als single page. Stop dan niet alle locators en bijbehorende methods in 1 single class page, maar splits deze op naar categorieën van functionaliteit en of secties/panelen van de website. Zo kan je methods en locators snel en eenvoudig terugvinden en onderhouden.

Herstructureren

Met het neerzetten van een basisstructuur kun je al heel gestructureerd aan de slag. Uiteraard is er altijd ruimte voor verbetering en is ieder project uniek. De genoemde structuur is dus slechts een voorbeeld. Het is altijd afhankelijk van vele factoren of een gekozen structuur werkbaar is. Zoals de omvang van het project, de hoeveelheid mensen die (efficiënt) parallel aan het project moeten kunnen werken, de frequentie waarmee zaken veranderen, etc.

Wat voor de een niet werkt, werkt voor de ander wel en andersom. Heb jij nu een structuur staan die voor jouw project niet werkt? Of heb je bovenstaande uitgeprobeerd en ben je daarmee niet tevreden? Onderneem dan actie! Wees niet bang voor (grootschalig) refactoring werk! Dwing hiervoor tijd af. Eenmaal begonnen? Merge dan snel naar de master. Wijzigingen die overal doorwerken, wil je vaak niet te lang laten liggen om teveel merge conflicten te voorkomen!

Als jij goed uitlegt aan je PO/Team waar je tegenaan loopt en wat een refactoring voor voordelen oplevert, zijn hiervoor altijd mogelijkheden, is mijn ervaring!

RestSharp

Tot zover de algemene projectstructuur van een Specflow/Cucumber project. Nu nog even over RestSharp:

RestSharp is dus een C# library te gebruiken voor het eenvoudig testen van REST API’s. In 2015 leek het onderhoud op de RestSharp library enigszins op te houden. Echter halverwege 2020 lijkt de library weer gereanimeerd te zijn met als gevolg in 2021 wat kleine wijzigingen. Onlangs in februari 2022 zelfs een nieuwe release met echt serieuze en grondige wijzigingen.

Voor bestaande projecten die reeds RestSharp gebruiken, betekent dit helaas veel refactor werk. Om maar een voorbeeld te geven: de meeste interfaces zijn verwijderd uit de library en dus niet meer bruikbaar.

Het goede nieuws is wel dat, voor zowel bestaande en nieuwe projecten, het gebruik van RestSharp weer enigszins vertrouwen geeft voor de toekomst. Persoonlijk gebruik ik liever libraries die actief onderhouden worden, en zodoende gebruik maken van de nieuwste inzichten/mogelijkheden en technieken, dan libraries die om onduidelijke redenen niet meer onderhouden worden.

Nog meer goed nieuws is dat de migration guide van RestSharp in vrij heldere taal aangeeft wat er dient te wijzigen of hoe je de library dan wel moet gebruiken.

Toch kan ik mij voorstellen dat er bij jou als tester of test automatiseerder wat vraagtekens oppopte bij het zien van de gebruikte code in een aantal van bovenstaande screenshots. Of bij het lezen van de migratiehandleiding zelf. Initieel was ik ook niet al te bekend met het gebruik van het (async) task type (met de nieuwste versie van RestSharp ben je min of meer gedwongen die te gebruiken). Daarom mijn aanbeveling je hierin ook eens te verdiepen door het lezen van deze 2 artikelen:

1) The basics of the task class

2) Task-based asynchronous pattern (TAP) in .NET: Introduction and overview

Gebruikt jouw project nog de oude versie van RestSharp? Hoe nu dan verder? Mijn advies is ga het gesprek aan met je team en de developers. Bepaal de impact voor een migratie en ook vooral de meerwaarde van de migratie (vergeet daarbij niet potentiële verbeteringen in stabiliteit en performance). Op basis van die uitkomsten dwing je tijd af bij je PO voor het eenmalig investeren van tijd in het migreren van je automatische testen.

Alvast experimenteren met een werkend voorbeeld? Clone dan mijn testproject behorende bij deze blog via mijn GitHub pagina.

Recap

Gebruik bovengenoemde handvatten voor het herkennen en/of overnemen van structuren. Zodoende kun je jouw project meer structuur bieden en dus efficiënter, en hopelijk met een hogere kwaliteit/onderhoudbare testcode, verder gaan. Jij blij, de developers blij en misschien zelfs de business blij die jij nu veel eenvoudiger kan rondleiden door jouw testen.

Heb je nog vragen naar aanleiding van de aangehaalde onderwerpen in deze blog of heb je code review feedback, neem dan gerust contact op met mij André Koene via AK@newspark.nl

Ik hoor graag van je!