Oefeningen TDD
Last updated
Last updated
In deze oefening gaan we met behulp van TDD een programma schrijven die de score gaat berekenen van een volledig spelletje bowling. Voor diegenen die nog nooit gebowld hebben of niet juist weten hoe de puntentelling is opgebouwd; hieronder vind je enkele links naar info:
Je moet dus de totale score van een spelletje berekenen, niet de lopende score weergeven (niet zoals de calculator dus).
De oefening wordt begeleid in stappen, het is de bedoeling dat je deze stappen volgt.
We gebruiken TDD als methode. Dat houdt dus in dat we de Red, Green, Refactor cyclus gaan volgen.
Zet alles klaar voor de eerste test: Maak een nieuw project BowlingGameScore en voeg een NUnit Test Project BowlingGameTests toe. Vergeet de 'Project Reference' en de using niet. Probeer in methode Test1 een instantie te maken van een klasse BowlingGame.
Zorg ervoor dat deze test slaagt. Let op: vermijd het schrijven van extra code. Creëer een nieuwe klasse BowlingGame.
Een volgende stap is dat we de score van een complete off-day game testen. De in bowlingmiddens bekende GlutterGame, Je gooit je bowlingbal steeds in de goot.
Schrijf de test When_Roll_GlutterGame_Returns_0(). Je creëert eerst een BowlingGame object. Roep 20 keer de (nog onbestaande) methode Roll aan met argument 0 (aantal kegels omvergeworpen) en vergelijk de score (property Score van class BowlingGame) met het verwachte resultaat. Deze test faalt (implementatie is nog niet verwezenlijkt).
Zorg dat de tweede test slaagt. Creëer een methode Roll die een integer argument heeft (het aantal omgeworpen kegels) en creëer een property die de score bijhoudt. Je hoeft er enkel voor te zorgen dat deze test slaagt.
Refactor je testen. De eerste test zit volledig in de tweede test, nl het instantiëren van het BowlingGame object. Je kan de eerste test dus schrappen. Doe dat. Laat de test(en) lopen en verifieer dat ze slaagt.
Een mogelijke volgende stap is een game waarin je bij elke worp een 1 gooit.
Schrijf de test When_Roll_AllOnes_Returns_20(). Je creëert eerst een BowlingGame object. Roep 20 keer de methode Roll aan met argument 1 (aantal kegels omvergeworpen) en vergelijk de score (property Score van class BowlingGame) met het verwachte resultaat. Deze test faalt (implementatie van Roll is nog niet juist).
Zorg dat de derde test slaagt. Verbeter de methode Roll zodat bij elke nieuwe worp de punten van de omgevallen kegels bij de score worden geteld.
Refactor je testen en de code. Allereerst maak je de setter van de property Score private. Test na je aanpassing opnieuw. Vervolgens kan je herhaalde code voor de instantiatie van het BowlingGame object verbeteren. Dat hebben we nog niet gezien in de cursus, dus dat krijg je cadeau:
Verwijder de instantiatie van het BowlingGame object uit je testen. Test opnieuw. Het testen is belangrijk om te voorkomen dat je nieuwe problemen introduceert tijdens de refactoring. Je hebt waarschijnlijk twee identieke loops in je testen staan om 20 keer een 0 of een 1 te gooien. Vervang deze loops door een (private) method RollMany met twee integer parameters rolls (aantal keren) en pins (aantal omvergeworpen kegels). Test nadien opnieuw om te verifiëren dat alles nog correct werkt.
Tijd om een Spare te testen. Een Spare is in één frame 10 kegels omgooien. Opgelet, een frame kan bestaan uit 1 of 2 worpen. Als je bij de eerste worp 10 kegels omgooit heb je een strike. Daarover meer later. De score is dan de 10 van de frame + het aantal omgevallen kegels bij je volgende worp. Het voorbeeld dat je in je test kan gebruiken is worp 1 - 5 kegels, worp 2 - 5 kegels en worp 3 - 3 kegels gevolgd door allemaal gootjes. De uiteindelijke score is dan voor frame 1 - 13 + frame 2 - 3 = 16.
Er is eerst wat refactoring nodig. Je hebt ten eerste het concept van frame dat we nog niet hebben meegenomen in de code. Verder heb je eigenlijk een historiek nodig van worpen om de score te kunnen bepalen. Je moet namelijk kunnen terugkijken naar een sequentie van worpen. Ook deze nieuwe code krijg je cadeau, maar je mag ook zelf eerst proberen of je er in lukt om de test hieronder te doen slagen. Doe in elk geval eerst de refactoring en blijf testen (zonder nieuwe test) alvorens je de nieuwe test schrijft.
Voor diegenen die er niet in slagen om de code te schrijven, of die de vraagstelling niet helemaal begrepen hebben volgt nu de nieuwe code. De nieuwe code doorloopt de tot nu toe gedefinieerde testen glansrijk:
Schrijf de test When_Roll_SpareAndThree_Returns_16(). Je roept de juiste methodes aan om de worpen aan de scorecalculator aan te bieden en vergelijkt de score met het verwachte resultaat. Deze test faalt.
Pas de code aan zodat de test slaagt.
Je kan de test of je een Spare hebt vervangen dooe een methode IsSpare met parameter rollIndex. Vervang ook
Door
En doe hetzelfde met je code voor de Spare score. Vergeet niet telkens te testen.
De strike. Je eerste worp van een frame kegelt alle kegels om. De score is dan de 10 van de frame + het aantal omgevallen kegels bij je volgende twee worpen. Het voorbeeld dat je in je test kan gebruiken is worp 1 - 10 kegels, worp 2 - 3 kegels en worp 3 - 4 kegels gevolgd door allemaal gootjes. De uiteindelijke score is dan voor frame 1 - 17 + frame 2 (twee worpen) - 7 = 24.
Dit is identiek aan test 4.
Het perfecte spel, dus niets dan strikes: 10 frames met telkens 1 worp en vervolgens nog eens 2 strikes.
Doe wat moet gedaan worden. Noem je test When_Roll_PerfectGame_Returns_300. De score voor een perfecte game is 300. Hoeveel worpen heb je? Moet je je code nog aanpassen?