Testen2.1 Ordina’s visie op Agile testen door Eric Jimmink, Anko Tijman, en vele anderen. illustraties: Waldemar van den Hof
Inleiding In deze tekst staat in het kort, welke visie Ordina heeft op Agile testen, en wat de ervaringen zijn bij het in praktijk brengen van die visie. In het derde jaar na het uitbrengen van “Testen2.0” is het logischerwijs tijd voor Testen2.1! Waar in 2.0 bewust de focus werd gelegd op de Agile mindset en de achtergronden van de Agile methodieken, is 2.1 meer concreet gericht op implementatie in projecten.
Leeswijzer Globaal is dit boekje opgebouwd uit 4 delen: 1. Testen2.1 - De visie / methodische beschrijving 2. Teamwork2.1 - De praktische invulling van de samenwerking, en voorbeelden van het gebruik van Tools 3. Testen2.1 zonder het label ‘Agile’ - Toepassen van Agile testen in projecten 4. Groeien naar Testen2.1 - Het implementatietraject voor een organisatie Aan het einde staan geen Templates en Quick Reference Cards. Wel locaties waar dergelijke documenten kunnen worden gedownload, want we geloven wel in het delen van kennis met de community. Tot besluit een aantal nuttige links, referenties, en een woordenlijst.
DEEL 1: Testen2.1 De visie op Agile testen Heel in het kort houdt effectief Agile werken in, dat alle werkzaamheden die nodig zijn om te komen werkende (geteste!) software, in een zo kort mogelijk tijdsbestek moet worden uitgevoerd. Aan de hand van een overzichtplaatje wordt nader toegelicht, hoe het multidisciplinaire team het werk en daarmee het testen invult.
Vroeg en multidisciplinair testen De business vraagt om een proces voor de totstandkoming van software waarbij ze tussentijds sturing kan geven aan het resultaat op basis van voortschrijdend inzicht, en de time-to-market wordt verkort. In dat licht is “zo vroeg mogelijk testen” een vereiste. Immers, snelle feedback kan veel dubbel werk vermijden. Bovendien wordt daarmee het testen van het kritieke pad van het project af gehaald. Testen wordt nadrukkelijk multidisciplinair: enerzijds omdat de feedback op alle terreinen moet worden gegeven (requirements, code, functioneel en overig applicatiegedrag), anderzijds omdat het gehele team interactie heeft met de klant en feedback op elkaars werk moet leveren om een gezamenlijk doel te behalen. In één plaatje tonen we de belangrijkste testactiviteiten die het multidisciplinaire team doet om kwalitatief hoogwaardige software te realiseren:
Acceptance TDD / Specificatie met voorbeelden De klant staat nadrukkelijk aan het roer, en heeft een belangrijke taak om het multidisciplinaire team te faciliteren bij de beeldvorming. Doelstelling moet zijn dat het team in staat wordt gesteld om in één keer het juiste product te maken voor de business. De ATDD cyclus omvat 4 stappen ( Discuss - Distill - Develop - Demo ), die herhaaldelijk worden doorlopen: 1. Bespreken. De eerste formulering van een user story (≈ requirement) roept doorgaans vragen op bij het team. Wat is bijvoorbeeld de intentie van de opdrachtgever, de achterliggende vraag van de business? Verder zal het team vragen hebben over een mogelijke invulling van de vraag; wanneer is het “goed genoeg”? 2. Distilleren. Uit de discussie komen voorbeelden naar voren, welke waar mogelijk één op één vertaald kunnen worden naar geautomatiseerde tests (checks). Die testen zijn slechts checks: een vaste tabel met uitgangssituaties, acties, en verwachte uitkomsten. 3. Bouwen. Het team gaat het onderdeel van het product vervolgens bouwen en daarbij zorg dragen dat alle checks ‘groen’ zijn bij de demo. 4. Demonstreren. Het behaalde resultaat wordt getoond aan de opdrachtgever. Er wordt feedback gegeven, en indien akkoord gaat het team door met het Bespreken van de volgende user story. De term 'Demonstreren' klinkt wellicht alsof er op dat moment formele acceptatie plaats vindt. En soms zal dat ook zo zijn, wanneer de demo wordt uitgevoerd in het kader van een oplevering van een iteratie. De cyclus kan ook meermalen worden doorlopen gedurende een iteratie; dan zal er meer sprake zijn van informele acceptatie op de demo-momenten. Als een team goed loopt en de klant veelvuldig of
doorlopend betrokken is bij het proces, dan is de gewenste vorm van samenwerking er een, waarbij er sprake is van continue acceptatie. Bij de klantorganisatie zijn doorgaans functioneel beheerders en eindgebruikers betrokken bij het proces van formele acceptatie van het eindproduct. Wanneer die gebruikers niet de tijd hebben gehad om het product te zien groeien, dan is er een groot risico voor het project, dat het niet direct verkrijgen van “de handtekening” leidt tot vertraging van het project als geheel.
De emotionele acceptatie gaat veel vloeiender als de gebruikers tussentijds het product hebben gezien, er wellicht mee hebben gewerkt, en een deel van hun feedback / wensen verwerkt zien in het eindresultaat. De formele acceptatie wordt daarmee gereduceerd tot een formaliteit, en is zo van het kritieke pad af. Aan het begin van een project zijn veelal niet alle namen bekend van de personen die namens de business betrokken moeten worden (of: willen worden) bij het acceptatieproces. Ook is het vooraf moeilijk in te schatten hoeveel tijd die “opgetrommelde testers” daadwerkelijk vrij kunnen maken voor het project. Geef het proces daarom wat tijd: nodig eindgebruikers uit voor de demo aan het einde van een iteratie, en geef ze de tijd om even te spelen met de applicatie. Na ongeveer 3 iteraties ontstaat er dan een “vaste kern” van enthousiaste mensen, die erbij blijven voor de rest van het traject. Anticipeer erop dat minstens een derde van de mensen afhaakt in verband met andere prioriteiten.
Specificatie met voorbeelden Een groot voordeel van ATDD is, dat het alle partijen tot elkaar brengt en samenwerking stimuleert. Als specificaties worden opgezet in door de business leesbare taal met veel voorbeelden, en worden bijgehouden gedurende het traject, dan vervullen deze de rol van levende documentatie. Het is dus niet meer nodig en zelfs niet meer wenselijk, om de ‘requirements’ tevens in een Word document bij te houden. De voor iedereen toegankelijke specificaties worden daarmee leidend als documentatie. Dat die specificaties tevens de vorm hebben van uitvoerbare testen waarmee snelle feedback kan worden gegenereerd, is een heel nuttig bijverschijnsel, maar niet de primaire waarde voor de business. Voor het latere beheer geeft het heel veel rust, dat de specificaties altijd up-to-date zijn, direct gekoppeld zijn aan de code, en uitvoerbaar blijven als testen. Een essentieel punt is evenwel, dat de ‘testen’ duidelijk aangeven, wat de achterliggende bedoeling van de business erbij is. Bij het onderhoudbaar maken van het geheel, is het belangrijk dat business en IT mensen hetzelfde jargon gaan hanteren, d.w.z. dat de terminologie van de business terug te vinden is in de specificaties en daarmee de voorbeelden, en ook in de code. Het bijwerken van documentatie is doorgaans moeilijk, omdat er gezocht moet worden naar de juiste plek in een document. Het gebruik van testen als documentatie lost dit probleem op: een test die moet worden bijgewerkt valt vanzelf op, omdat deze ‘rood’ is geworden. Gebruik verder tags om het overzicht te bewaren.
Unit- en integratietesten De beste resultaten worden bereikt wanneer het gehele team het werk zodanig inricht dat er zo vroeg mogelijk feedback wordt gegenereerd. Een noodzakelijke voorwaarde voor het effectief kunnen samenwerken, is continue integratie (CI). Dit houdt in dat alle code in een gezamenlijk versiebeheersysteem wordt bewaard, en een automatisch proces de wijzigingen (check-ins) detecteert en periodiek compileert tot één gezamenlijk product. Zo wordt er automatisch hele snelle feedback gegeven
indien er inconsistenties in de codebase zitten, bijvoorbeeld omdat programmeurs conflicterende aannames maken. De juiste werking van de code kan geborgd worden, door ieder klein stukje van de code te valideren middels het schrijven van testcode. Die testcode (unit test) wordt vervolgens aangeroepen bij iedere continuous integration build van het systeem. Juist omdat het de bedoeling is om alle unit testen voortdurend te draaien, is het belangrijk dat ze snel worden uitgevoerd. Dit wordt deels gerealiseerd door units geïsoleerd te testen, en de interactie met andere onderdelen te vervangen door zogenaamde mock objects. Dat neemt niet weg dat er tijdrovende testen kunnen bestaan. Veel teams kiezen ervoor om dergelijke tijdrovende testen uit te sluiten van de CI build, en te plaatsen in een apart build proces dat bijvoorbeeld ’s nachts wordt gedraaid: de nightly build. Het verdient aanbeveling om dit al vanaf het begin van het project op te zetten en te oefenen zodat een test snel kan worden verplaatst tussen de twee build processen. Veel teams gaan nog een stap verder, door uitgebreide unit testen te schrijven vóórdat de bijbehorende productiecode wordt gerealiseerd. Dit gebruik wordt Test Driven Development genoemd. Dit is nadrukkelijk een iteratief proces van kleine, beheerste stapjes waarbij de focus ligt op het goed krijgen van het design en het borgen van de onderhoudbaarheid. Stappen voor het toepassen van Test Driven Development (Red – Green – Refactor): 1. Voeg één of meer tests toe (voor een nog te schrijven stukje code) 2. Voer alle tests uit en zie er op toe dat de nieuw toegevoegde tests falen 3. Schrijf een minimum aan code om de tests te doen slagen 4. Draai alle tests opnieuw; nu moeten ze allemaal “groen” zijn 5. Refactor de code: maak het eenvoudiger c.q. beter onderhoudbaar 6. Voer nogmaals alle testen uit Stap 5, refactoring, is een integraal onderdeel van TDD. Het nadenken of een eerste oplossing misschien eenvoudiger kan, en die vereenvoudiging dan ook daadwerkelijk doorvoeren, vermindert de kans op fouten. Ook verbetert die werkwijze het overzicht, en het vertrouwen dat de gekozen unit testen voldoende dekking hebben. Veel teams hanteren reviews of pair programming om te zorgen dat alle code en alle unit tests aan een second opinion worden onderworpen. De code wordt nog beter onderhoudbaar, omdat gedachtekronkels worden beperkt en er meer mogelijkheden voor refactoring worden onderkend. Bovendien vindt er op die manier meer uitwisseling van kennis plaats. Een ‘tester’ die voldoende technisch onderlegd is om de code en de unit testen te reviewen, zal dat zeker niet uit de weg gaan. Immers, vanuit zijn expertise kan hij aanvullingen aandragen, en overlap met zijn eigen testen tegen gaan. Overigens geldt dat wanneer een programmeur een korte uitleg (walkthrough) bij de code geeft, iedere tester in staat zou moeten zijn om de unit testen te lezen, en aanwijzingen te geven voor aanvullende testgevallen. Is de code na zo’n uitleg nog onvoldoende leesbaar, dan is die code waarschijnlijk ook niet zo goed onderhoudbaar. Bij het top-down uitwerken van een requirement volgens TDD, zal een programmeur regelmatig mock objects nodig hebben voor onderdelen, die hij of zij over enkele minuten wil gaan schrijven. Dat roept enige weerstand op. Een pragmatische insteek is prima, zolang het maar geen afbreuk doet aan het doel van de exercitie, namelijk het goed krijgen van het design.
Kijk uit voor de mini waterval! Als een team heel kwaliteitsbewust is, moet men er voor waken dat de ene testactiviteit de andere testactiviteit niet gaat hinderen. Als een team bijvoorbeeld heel veel unit testen schrijft voor iedere feature, dan moet het wel zo zijn dat de testers een testbaar product ontvangen om hun testen op uit te voeren, lang voordat alle checks zijn geïmplementeerd. De checks en de onderzoekende testen moeten beiden worden uitgevoerd voordat een fragment van het product “Done” kan worden genoemd. Er is echter géén regel dat alle checks moeten zijn voltooid voordat het onderzoekende testen kan gaan beginnen! Uit onze ervaringen blijkt dat de meeste effectieve aanpak eentje is waarbij op een pragmatische manier de beschikbare hoeveelheid testtijd wordt gemaximaliseerd.
Al deze unit testen zijn in feite geen testen, maar checks: de focus ligt op het borgen dat de code goed in elkaar zit omdat alle checks steeds moeten slagen. Het gedrag van de applicatie als geheel kan daarna worden onderzocht door te gaan testen. Beide invalshoeken vullen elkaar aan. Dat wil zeggen: de programmeur die “bevestigend” test om de juiste werking aan te tonen, vindt andere fouten dan de tester die sceptisch ingesteld te werk gaat en in de huid kruipt van een ondeugende gebruiker. Waar het mogelijk is om testen op integratieniveau te automatiseren, loont dat zeker de moeite. De praktijk leert namelijk dat op het integratieniveau veel fouten optreden. Het controleren van de bedrijfregels kan in de regel wel op dit niveau, maar niet op het niveau van de unit testen. Vaak is er niet alleen sprake van een iets hoger integratieniveau in de zin dat de verschillende units samenkomen tot eenheden in termen van de business processen. Veelal is er ook sprake van het gebruik van externe bronnen, zoals webservices en databases. De implementatie van integratietesten kan in de regel met precies dezelfde tools als unit testen worden uitgevoerd. Alleen is de focus nu anders: het gaat met name om het controleren van de interfaces, niet zozeer om de juistheid van de code en het design. Ook geldt hier het principe van testen in isolatie: voor het testen van één integratie worden onderdelen die eigenlijk buiten de scope van de test vallen, vervangen door stubs of mock objects. Omdat veel integratietesten relatief langzaam zullen zijn (het aanroepen van een webservice kan zomaar een volle seconde vergen), zullen veel integratietesten terecht komen in een nightly build. Nog meer dan bij de unit testen geldt dat dit een uitgelezen mogelijkheid biedt voor het samenwerken tussen testers en programmeurs. Samen bezitten ze testexpertise en kennis van het automatiseren van testen. Het testen van database interactie is een bijzondere tak van sport. Er zijn frameworks om een database op dezelfde manier te behandelen als een object in een unit test. Enkele uitzonderingen daargelaten, is de uitvoeringssnelheid(*) echter zodanig, dat veel van dergelijke testen in een nightly build zouden thuishoren. De ervaring leert dat fouten in bijvoorbeeld het opslaan van gegevens in een database, erg moeilijk te vinden zijn bij testen op een hoger niveau zoals een gebruikersinterface. Het advies is dus om dergelijke testen wel degelijk uit te voeren. Een complicerende factor is het moderne gebruik om te werken met frameworks, welke database queries genereren bij een data model. In zo’n geval is het weinig zinvol om op het laagste niveau veel inspanning te steken in het checken van de juiste werking van de gegenereerde code. Kies in plaats daarvan voor het uitvoeren van veel (integratie)testen op een iets hoger niveau, zodat duidelijk is dat de bedrijfsregels goed worden ondersteund met de gekozen oplossing. (*):
Hierboven werd gesteld dat database queries langzaam zijn. Er is echter een belangrijke uitzondering, die geleidelijk aan populariteit wint. In memory database systemen zijn dermate veel sneller dan reguliere database systemen, dat nagenoeg iedere query in een test gewoon snel genoeg is voor de CI build. Ook als men geen gebruik maakt van een in memory database systeem, is het natuurlijk wel mogelijk om een deel van de unit testen op de database toe te laten tot de CI build. Voeg gewoon logging toe, zodat duidelijk wordt hoeveel tijd (doorgaans uitgedrukt in milliseconden) een test vergt. Zodoende kan gericht worden gekozen voor het plaatsen van de test in de CI build of de nightly build.
Exploratory Testen Eenvoudig gepresenteerd, komt Exploratory Testen (ET) neer op het tegelijk specificeren en uitvoeren van testen. Er worden ‘en passant’ dus wel degelijk specificatietechnieken gebruikt, en het proces is wezenlijk meer dan error guessing. De reden dat er binnen een Agile context vaak voor gekozen wordt om te beginnen met Exploratory Testen, is dat er veel waarde wordt gehecht aan het snel geven van feedback. (Als er met een minimum aan voorbereidingstijd begonnen kan worden met de testuitvoer, dan kunnen bevindingen zeer goedkoop hersteld worden, omdat de materie bij de programmeur nog vers in het geheugen ligt.) Op basis van de eerste ervaringen kan dan besloten worden om verder te gaan met een andere testtechniek. Om effectief met elkaar samen te werken en voor elkaar te kunnen bijspringen, is het in een Agile project belangrijk om inzage te geven in hoe er getest wordt. Immers, het kan gebeuren dat de persoon die de test uitvoert, een andere is dan degene die de test heeft voorbereid. Is er bij Exploratory Testing dan ook sprake van testvoorbereiding? Ja. Het is een goed gebruik om eerst een zogenaamde test charter op te stellen. Daarin staan geen uitgewerkte testgevallen, maar wel (globaal) wat er getest gaat worden, met
welke intenties en aandachtspunten de test wordt uitgevoerd, en in welk tijdsbestek. Het is gebruikelijk om ET uit te voeren als een time-boxed activiteit. Als techniek schrijft ET voor dat na afloop van de timebox de charter is aangevuld met de testresultaten, en dat er in een korte nabespreking (debriefing) wordt besloten welk vervolg er aan de test wordt gegeven. Maak de charters c.q. testsessies ook niet te lang, beslist niet langer dan 4 uur. Vaak is 90 minuten al ruim voldoende. In veel gevallen lijken de globaal beschreven testsituaties op een checklist. De uitvoerende tester wordt gevraagd om zich beslist niet te beperken tot de beschreven testen, maar gaandeweg nieuwe testen te formuleren en uit te voeren op basis van de eerste ervaringen en bevindingen. Tijdens het uitvoeren van de testen moet de charter dus niet alleen wordt aangevuld met de testresultaten en bevindingen. Er moet ook (kort) worden beschreven welke testsituaties er gaandeweg zijn toegevoegd en uitgevoerd. De ingevulde testcharter hoort na de sessie (en de debriefing) te worden bewaard en toegevoegd aan de oplevering aan het einde van de iteratie. Als er veel charters zijn (8 of meer), of wanneer functionele delen zijn opgesplitst en ondergebracht in meerdere charters, voeg dan ook een overzichtsdocument toe.
Fouten zijn vaak geclusterd De ervaring leert dat fouten binnen software vrijwel nooit gelijkmatig zijn verspreid over de applicatie. Er zijn altijd onderdelen die eruit springen en meer fouten opleveren, bijvoorbeeld omdat de materie als zeer complex werd ervaren, of de requirements niet goed zijn begrepen. Een time-boxed (Exploratory) test kan goed gebruikt worden als graadmeter voor een onderdeel. Daarna kan het team besluiten wat de beste vervolgactie is: stoppen met testen, fouten corrigeren en verder testen met een meer formele testtechniek, of zelfs het kiezen van een andere oplossing of het herschrijven van de code. Een tester die Exploratory Testing als techniek toepast, maakt gebruik van het ervaringsfeit, dat fouten veelal geclusterd voorkomen. Waar een fout wordt gevonden, loont het de moeite om juist in die omgeving verder te zoeken naar fouten. Ook is het waarschijnlijk dat een gerelateerde fout elders in de code voorkomt: soms wordt een fout nu eenmaal pas gevonden nadat deze als tekst of als gedachtekronkel is gedupliceerd.
Uitvoering van Exploratory Testen zal grotendeels handmatig plaatsvinden. Tools kunnen goed ingezet worden voor bijvoorbeeld het versnellen van het bereiken van de uitgangssituatie voor een test. Ook kan er in sommige gevallen gespeeld worden met parameters in scripts, om zodoende variatie aan te brengen in het gebruikersgedrag. Bij Exploratory Testing worden er wel degelijk testtechnieken gebruikt. Vaak gebeurt dat echter en passant, op basis van routine. Een ervaren tester past bijvoorbeeld grenswaarden toe, zonder deze te hoeven uitschrijven. Ook heuristieken zijn onderdeel van het arsenaal dat een tester toepast. Stel bijvoorbeeld dat een testcharter neerkomt op het onderzoeken van de validaties in een aantal schermen van een gebruikersinterface. De meest voorkomende fout in validaties, is dat ze afwezig of onvolledig zijn. Daarnaast kan het gemakkelijk voorkomen dat grenswaarde controles verkeerd zijn geïmplementeerd. Het uitschrijven van alle controles die worden uitgevoerd voegt weinig waarde toe. Maak gewoon algemene afspraken over de voor de hand liggende controles, en leg deze ergens vast in een checklist. Denk daarbij aan het leeg laten van verplichte velden, het proberen van onjuiste waarden en tekens in tekstvelden, en grenswaarden voor numerieke velden. In de testcharter horen naast de schermen alleen de bedrijfsregels vermeld te staan, die expliciet moeten worden gecontroleerd. Tijdens de uitvoering hoeft in de testcharter dan alleen de voortgang te worden vermeld, welke bevindingen er naar voren kwamen, en welke vervolgacties (verdere testen op basis van de bevindingen) er gekozen zijn.
Niet functioneel testen In principe horen alle testsoorten binnen de iteratie te worden uitgevoerd, teneinde de feedback lus zo kort mogelijk te houden. Dat geldt dus ook voor testen van kwaliteitsattributen zoals performance en security. Richt daartoe één of meer aparte testomgevingen in, welke niet gebruikt worden voor de functionele testen. De praktijk leert overigens dat in bijna alle gevallen er veel meer waarde gehecht wordt aan informele metingen dan aan ‘exacte metingen’ op basis van gecontroleerde omgevingen en de bijbehorende (dure) tools. Een programmeur heeft namelijk genoeg aan indicatieve metingen en trends voor het aanbrengen van correcties. Een beheerafdeling wil vooral bewezen zien dat de performance niet meer dan lineair achteruit gaat.
Het is belangrijk om deze testen van kwaliteitsattributen op de juiste plaats uit te zetten in de tijd. Een eventuele correctie kan namelijk heel duur zijn, omdat het vaak niet zozeer de code is die wordt aangepast, als wel de onderliggende architectuur. Richt daarom in ieder project een zogenaamd Proof of Concept in, waarop de metingen van de gekozen kwaliteitsattributen vroegtijdig kan plaatsvinden. Sowieso is het wenselijk dat er sprake is van een doelgerichte architectuur, waarbij de testbaarheid van het geheel in het achterhoofd wordt gehouden. Een goed gebruik is bijvoorbeeld de separation of concerns; dit houdt in dat afgebakende onderdelen (vaak: lagen) in een applicatie zich met verschillende zaken bezighouden. Als bijvoorbeeld de bedrijfsregels deels verstopt zitten in de database, dan is het waarschijnlijk moeilijk om als team het overzicht te behouden, en te bepalen hoe een wijziging getest moet worden. Zijn er heel veel kritische onderdelen, in de zin dat er bijna iedere iteratie nieuwe onderdelen bijkomen die getest moeten worden op bijvoorbeeld performance, dan zal het Proof of Concept geen uitsluitsel geven. Richt in dat geval de testen zodanig in, dat deze binnen de iteratie kunnen worden uitgevoerd. Kies bewust voor een beperkte ‘levensduur’ van het merendeel van de testen, omdat het beheer ervan in latere iteraties kostbaar zal zijn. Selecteer aan het einde van iteratie slechts een deel van de testen om aan te houden als onderdeel van de regressie suite. Binnen de iteratie is dus het advies dus: doe zoveel mogelijk als onderdeel van de Definition of Done. Dat neemt niet weg dat er een zekere testverplichting over blijft aan het einde van de rit. Projectmatig moet de intentie zijn, dat een test aan het einde een bevestigend karakter krijgt. Als de risico’s vooraf goed zijn ingeschat, zijn er in de slotfase geen dure verrassingen meer. Voor sommige testen is het heel moeilijk om deze in te passen in de Agile procescyclus. Denk daarbij bijvoorbeeld aan het testen met ketenpartners, die er zelf een andere release cyclus op na houden. Dan is het belangrijk om goede afspraken te maken over het testen van de interfaces. Voor de eigen ontwikkeling is het prima om het merendeel van de testen binnen de iteratie uit te voeren tegen stubs. Voorafgaande aan het ‘live’ gaan van een product zal men de test met zo min mogelijk stubs willen uitvoeren. Die testuitvoering alsmede eventuele herstelwerkzaamheden zitten per definitie op het kritieke pad; vroeg testen moet dit tot een minimum beperken.
Definition of Done Het team legt vast welke kwaliteitsstappen ze gaan uitvoeren om te komen tot een kwalitatief goede oplevering van een productierijp systeem. Dat kwaliteitskader (de zogenaamde Definition of Done) geeft veel richting aan het werk van het team. Tijdsinschattingen worden nauwkeuriger, en de opdeling van het werk eenvoudiger. Verwachtingen bij de klant worden expliciet gemanaged. Namens de business is het niet alleen de product owner die criteria kan opleggen, waar iedere oplevering aan moet voldoen. Ook een beheerafdeling heeft doorgaans eisen, die het team moet overnemen, en zal incalculeren bij het inschatten van het werk. De Definition of Done is ook mede bepalend voor de benodigde samenstelling van het team. Ontbreekt er een vaardigheid aan het team welke nodig is om alle stappen in de Definition of Done tot een goed einde te brengen, dan is dat een goede aanleiding voor het uitbreiden van het team. Indien een organisatie beleid heeft aangaande de inhoud van een Definition of Done, dan biedt dat een belangrijke mogelijkheid voor commercieel succes. De kwaliteit van het product kan en moet benadrukt worden, in plaats van de lage prijs waarvoor het wordt gerealiseerd.
Documentatie bij oplevering De op te leveren documentatie moet onderdeel zijn van de afspraken omtrent de Definition of Done. Het team zal zelf een beeld hebben van de benodigde systeemdocumentatie; een beheerafdeling kan daar allicht nadere eisen aan stellen. Het is in elk geval billijk om te verlangen dat op het moment van oplevering de documenten up-to-date zijn met de realisatie van het product. Veel teams werken met gegenereerde systeemdocumentatie, die bijvoorbeeld door het gebruik van labels in de code en in het versiebeheersysteem de wijzigingen en de release notes kunnen oplepelen. Doordat het een geautomatiseerd proces betreft, is het team er geen tijd aan kwijt, en worden er geen fouten in gemaakt (anders dan het achterwege laten van de labels). Een ander voor de hand liggend minimum om op te leveren, is in termen van de business een formulering van wat er “nieuw” in een release zit. Gelukkig biedt het proces daar een eenvoudige invulling voor: er moet allicht een lijst zijn van alle user stories die voldoen aan de Definition of Done. Houd die lijst dus goed bij, en let er op dat de user
stories zo veel mogelijk geformuleerd zijn in termen van de business. In feite is deze stap gegarandeerd, als het team op een goede manier ATDD / specificeren met voorbeelden heeft ingericht en ingebed in de organisatie. Vanuit testoogpunt is het belangrijk dat de opgeleverde testware leesbaar is voor het nageslacht. Dit is namelijk een valkuil voor veel teams: dat de programmeurs hun zaakjes goed voor elkaar hebben en de code volledig in source control hebben, en dat de testware achter blijft.
Tester is een rol, geen functie Voor veel testen is tijdige uitvoering van de test belangrijker dan de testkennis van de persoon die de uitvoert. Slechts een klein deel van de testen vereist bij de uitvoering de expertise van de expert. Door zo veel mogelijk testen uit te laten voeren door de bouwers, kunnen zij zorg dragen voor het automatiseren en het beheren daarvan. Al met al verandert de ‘richting van de werkverschaffing’. De tester is niet langer het afvoerputje waar het gehele team zijn testwerk op uitstort. In plaats daarvan zorgt de testspecialist (Gojko Adzic: ‘test architect’) ervoor dat de juiste dingen getest worden en reikt hij of zij de testtaken aan voor de bouwers. Een goed voorbeeld van een teamlid voor wie testen een rol zal zijn, is de ontwerper of analist. Het is mogelijk dat in de latere iteraties een substantieel deel van de analyse al is uitgevoerd, in de zin dat het geen dagtaak meer is. Voor het team is het dan heel waardevol, als die persoon wel fulltime bij het team blijft, en actief meehelpt met testen. Het betreft immers iemand met uitgebreide kennis van het gewenste gedrag van het systeem.
Domein testers en Systeem testers In vrijwel ieder project is er behoefte aan een testaanpak op twee verschillende fronten. Denk bijvoorbeeld aan een service geörienteerde oplossing (SOA): op een hoog niveau waar de services worden samengevoegd tot business processen, is het voor het testen randvoorwaardelijk dat de afzonderlijke services al uitvoerig zijn getest. Op dat hoge niveau worden de testsituaties omschreven in termen van de business, en worden de testen uitgevoerd in samenwerking met domeinspecialisten. Een tester op dat niveau moet domeinkennis kunnen toepassen, en goed kunnen communiceren en meedenken met mensen van de business. Voor het testen van de afzonderlijke services is een heel andere aanpak nodig. Dat vergt namelijk rechtstreeks contact met de bouwers binnen het team, gebruik van specialistische tools, en kennis van het implementatieplatform. Daarbij worden vaker formele testspecificatietechnieken gebruikt. De benodigde vaardigheden voor deze systeemtesters zijn daarmee wezenlijk verschillend van de vaardigheden voor domeintesters. Het is goed als een tester zich op beide terreinen ontwikkelt. Echter: vrijwel iedere tester heeft slechts de affiniteit en de potentie om op één van beide terreinen te excelleren, als Domeintester of als Systeemtester. De aanbeveling is om als organisatie verschillende carrièrepaden en opleidingen aan te bieden, en mensen dus te laten kiezen. Binnen een multidisciplinair team zijn beide rollen (d.w.z. de rol van domeintester en de rol van systeemtester) nodig. Als het team op beide rollen een testspecialist wil hebben, dan heeft dat consequenties voor de gewenste grootte van het team. De Scrum theorie wordt vaak uitgelegd als: teams van (4)5 tot 7 personen met een zekere voorkeur voor de kleinere teamgrootte. Onze voorkeur (gebaseerd op ervaringen uit de praktijk) gaat uit naar een team van 6 tot 9 personen met daarin 2 of 3 testspecialisten. Om beide testrollen goed uit de verf te laten komen ligt de minimum grootte voor het team nu eenmaal ietsje hoger.
Duale rollen Het werk vraagt een zeker mate van flexibele inzet. De benodigde inspanning per discipline varieert in de tijd. Het is daarom zeer wenselijk als enkele teamleden in staat zijn om meer dan één rol in te vullen. Bijvoorbeeld: ontwerper of programmeur, en tester. Hoeveel mensen zullen een dergelijke duale rol kiezen, als de organisatie dat niet ondersteunt met een carrièrepad dat goed wordt gewaardeerd? Het gaat niet alleen om de financiële aspecten. Hoogstwaarschijnlijk heeft een medewerker meer tijd nodig om up-to-date te blijven in twee disciplines dan in één vakgebied. Het beschikbaar stellen van uren voor het bijhouden van de vakgebieden zou een goed extraatje kunnen zijn voor die medewerkers. Hen naar meer trainingen en conferenties toe sturen zou ook heel positief worden ontvangen.
Team == Product Een kwalitatief hoogstaand product maken vereist een heel goed lopend team. Is er iets mis in de onderlinge communicatie, of ontbreekt er iets aan de kennis en vaardigheden van de teamleden, dan zal dat zijn weerslag hebben op het eindproduct. Als de klant onvoldoende tijd kan vrijmaken voor het team, of niet met passie de intenties achter de vraagstelling voor het product kan verwoorden, dan beperkt dat de mogelijkheden om samen te komen tot een prachtige creatieve oplossing. De attitude van de teamleden moet in de eerste plaats resultaatgericht zijn. Dat houdt in dat er geen persoonlijke doelen worden nagestreefd, maar één gezamenlijk doel. Alle activiteiten van de teamleden moeten bijdragen in het als team voldoen aan de Definition of Done. In een iteratief proces is het een natuurlijk en onvermijdelijk fenomeen, dat er in de slotfase meer testwerk is dan in het begin. Van de teamleden wordt verwacht dat ze “testtaken” volledig gemotiveerd oppakken, ook als dat niet hun specialisme is. Wanneer een team begint met een Agile werkwijze, dan zal het zo zijn dat lang niet iedereen even “test infected” is. Ook in ervaren team zal het zijn dat er voor de testspecialist niet alleen een rol is weggelegd in het aanreiken van testgevallen, maar juist ook in het overdragen van testkennis. Evenzo zal een tester kennis opbouwen van het implementatieplatform, en kan iedereen domeinkennis leren uit de interactie met de klant. Als organisatie is het belangrijk om een lerende omgeving te creëren voor het team, en het team niet alleen aan te sturen of af te rekenen op productiviteit op de korte termijn. Geef tijd voor individuele ontwikkeling. Dit gaat zich later terug betalen. Houd teams bij elkaar, en maak gebruik van teamleden met duale rollen om accentverschuivingen in de werklast op te vangen. Als team is het belangrijk om te leren van de fouten die er gemaakt worden. Ook als het goed lijkt te gaan, kan vrijwel ieder team nog verbeterpunten aandragen voor zowel hun eigen proces, als de organisatie om hen heen. Retrospectives (evaluaties per iteratie) zijn hiervoor een uitstekend middel; sla die stap in het proces dus nooit over. Teamleden kunnen actief van elkaar leren, door veel aan kennisoverdracht te doen, en regelmatig taken uit te voeren buiten het eigen specialisme. Pair programming kan voor heel veel taken worden toegepast. Voor wat betreft het lerende effect worden de beste resultaten bereikt als “de expert” niet als bestuurder achter de knoppen zit, maar als
navigator. Ook de kwaliteit van het eindresultaat is in die opstelling vaak beter, omdat de juiste persoon in de corrigerende rol zit. Als de meest ervaren medewerker achter de knoppen zou zitten, dan is er al gauw een drempel, die de “leerling” belemmert in het uitspreken van twijfel over de juistheid. We kunnen dit vergelijken met de luchtvaart: daar hebben ze geconstateerd dat de landing het meest veilig is wanneer deze wordt uitgevoerd door de copiloot. Waar nodig zal de captain niet schromen om in te grijpen.
Collective test ownership Een algemeen toegepaste werkwijze vanuit Extreme Programming (XP) is collective code ownership. Dat houdt in dat alle teamleden gezamenlijk de code beheren, volledige inzage hebben, en bijvoorbeeld ook de fouten oplossen in code die door een ander is geschreven. Dat impliceert dat er één gezamenlijk systeem moet zijn voor het beheren van de code, en uiteraard is het ook alleen werkbaar als er tevens continuous integration wordt toegepast. Voorts moet er sprake zijn van veel uitwisseling van kennis, bijvoorbeeld door middel van reviews of pair programming. Sommige teams gaan nog een stap verder, door ook alle testware in source control te plaatsen, en deze als team gezamenlijk te beheren. Elisabeth Hendrickson noemt dat: collective test ownership. Om collective test ownership in praktijk mogelijk te maken, heeft een team nog meer nodig. Coding standards zullen ook moeten worden doorgetrokken naar testdocumenten en testcode. Testen worden zo dicht mogelijk gekoppeld aan de code. De vertaalslag van requirements naar testen moet duidelijk en traceerbaar zijn. Bij wijzigingen in de code of in de requirements moet het gehele team over voldoende overzicht beschikken, om adequaat te kunnen beslissen over de testen die moeten worden uitgevoerd, en hoe deze verder moeten worden beheerd. Veel van de testen worden geautomatiseerd. Het inrichten van de testautomatisering wordt belegd bij de bouwers binnen het team en de testers zorgen dat de juiste zaken getest worden. Het beheer van de testen komt daarna bij alle leden van het team te liggen. Dat houdt in dat kennis actief moet worden gedeeld, en er regelmatig in paren zal worden gewerkt.
Gelijkheid binnen het team Het klinkt zo gemakkelijk: gelijke monniken, gelijke kappen. Het is echter wel een hele mentaliteitsverandering om collective test ownership in te voeren, en beslist eentje die weerstand oproept. Nog altijd zien veel programmeurs het testen als monnikenwerk, iets waar ze bewust niet voor hebben gekozen. Toch kan het zomaar gebeuren, dat van een programmeur of een analist wordt verlangd, dat hij of zij enthousiast gaat meehelpen met het uitvoeren van testen die niet zijn geautomatiseerd! Bereidheid om werk uit te voeren en zich te ontwikkelen buiten de eigen comfort zone is dus zeker een vereiste. Uiteraard geldt dat voor alle teamleden, ongeacht hun rol. Wat ook belangrijk is voor de benodigde gelijkheid binnen het team, is dat iedereen wordt behandeld als een volwaardige professional, die niet hoeft te worden beknot in zijn of haar rechten. Geef dus een tester gewoon schrijfrechten op de code en de unit tests, en geef een bouwer de mogelijkheid om met één druk op de knop de inhoud van een compleet testscript te wissen. Ze zijn immers allemaal professioneel genoeg om hun rechten niet te misbruiken (en alles staat toch in source control). Wat vermeden wordt met het uitdelen van full control, is dat er berichtenverkeer buiten de codebase nodig is. Dat laatste levert alleen maar verwarring en vertraging op, en is dus een vorm van verspilling. Een medewerker die onvoldoende technisch onderlegd is om zelfstandig een test te implementeren of aan te passen, kan deze allicht wel met een paar commentaarregeltjes omschrijven in de code. Maak afspraken over de te gebruiken tags in de testcode, en richt het build proces er op in.
Als een team er serieus werk van wil maken om gezamenlijk de testen te beheren, dan moet de testcode zo veel mogelijk gezien worden als reguliere code. Testcode heeft onderhoud nodig. Testcode moet op een onderhoudbare wijze worden opgezet. Allicht moeten teamleden elkaars testcode reviewen. Mogelijk komt er uit zo’n review, dat een test eenvoudiger kan, of bijvoorbeeld herhalingen bevat. Kortom: refactoring van testcode zou ook bespreekbaar moeten zijn. Het enige probleem daarbij is dat er geen vangnet van geautomatiseerde testen voorhanden lijkt te zijn, om wijzigingen aan de testcode mee te borgen. Dat is echter niet helemaal waar: houd bij het refactoren van testcode de productiecode constant, en zie er op toe dat de testen “groen” blijven!
Samenvattend: wat is nu de rol van de tester? Het testen moet zo veel mogelijk van het kritieke pad van het project af, vroeg beginnen en zo veel mogelijk parallel met de bouw worden uitgevoerd. Daarmee is de tijd van validatie door een onafhankelijk QA team voorbij. Veel checks worden nu al uitgevoerd door de bouwers in een multidisciplinair team. De testspecialist binnen zo’n team heeft verschillende rollen, waarvan testuitvoerder er slechts ééntje is. Voorts is de tester: • Dirigent. Hij zorgt er voor, dat de overige teamleden de juiste dingen testen, en dat dit alles harmonieus gebeurt. • Teamspeler. Hij kan snel schakelen, en feedback leveren waar dat op dat moment nodig is voor het team. • Analist. Het samen verbeteren van de requirements (voorbeelden?) geeft richting aan het verdere testen. • Kennisdeler. Door testkennis te delen met andere teamleden, stelt hij hen in staat effectiever te testen. • Bruggenbouwer. De tester communiceert met vrijwel alle rollen in de business en het IT project. Wees dus objectief als tester, en deel je kennis. Behoud het overzicht, en zorg dat eenieder elkaar vindt en helpt met het geven van vroege feedback.