Voorbereiding
1. Van executeerbare specificatie naar geautomatiseerde tests
In de vorige les hebben we gekeken hoe Gherkin features met bijbehorende scenario's tot stand kunnen komen in samenwerking met stakeholders.
De simpele daad van samenwerken om scenario's uit te schrijven is een goede manier om meer inzicht te krijgen in het probleem dat je aan het oplossen bent, verborgen aannames te elimineren en risico's te verminderen. Veel teams ervaren dat alleen deze gesprekken al het aantal defecten aanzienlijk verminderen en de kwaliteit van de opgeleverde functies verbeteren. Daarnaast is een van de krachtigste dingen aan BDD de gedachte dat de voorbeelden op de een of andere manier uitvoerbaar kunnen worden, zodat ze tegelijkertijd geautomatiseerde (acceptatie-)testen en specificaties worden.
Ter voorbereiding op aankomende les zul je zien hoe Gherkin scenario's omgezet kunnen worden in uitvoerbare specificaties met behulp van Java, Cucumber en Apache Maven.
De BDD-scenario's leggen we vast in zogenaamde feature bestanden in de broncode. Deze bestanden hebben een ".feature" achtervoegsel en zijn ontworpen om, zoals de naam al zegt, alle scenario's te bevatten die het verwachte systeem gedrag van een bepaalde functie beschrijven.
Een gebruikelijke conventie voor Java/Cucumber is om de feature bestanden in de map src/test/resources/features te plaatsen.
Binnen de feature map kunnen functiebestanden worden gegroepeerd (in packages), bijvoorbeeld op sleutel functionaliteiten van hoog niveau of bepaalde thema's/epics.
Begin niet te vroeg met nadenken over groeperen, voorlopig is één package genoeg.
:::
✏️ Open het bowling-project in Intellij als maven project <jouw repo van week 5>/weekopdracht/jouw-uitwerking/bowling>.
✏️ Neem de bowling scenario's van de vorige les over in het bestaande feature bestand (bowling_score.feature) in de submap <./src/test/resources/features>.
Dit telt nu als een uitvoerbare specificatie. Hoewel er geen code achter het scenario zit om het iets te laten testen, kun je het wel uitvoeren. Als je het uitvoert, zullen de testen mislukken (omdat er geen code is om ze te implementeren), maar het zal nog steeds een output genereren met de scenario's die nog geïmplementeerd moeten worden.
De taal die in de scenario's wordt gebruikt komt heel dicht bij de termen die de stakeholders gebruikten in de gesprekken met het team. Wanneer de scenario's in de testrapporten verschijnen, maakt het gebruik van deze vertrouwde taal het makkelijker voor testers, eindgebruikers en andere (niet-ontwikkelaars) om te begrijpen welke functies worden getest en hoe ze worden getest.
:::
2. Automatiseren van de executeerbare specificatie
De volgende stap is om de uitvoerbare specificatie om te zetten naar geautomatiseerde testen. Hiervoor schrijf je de (testautomatisering) code die wordt aangeroepen wanneer het scenario wordt uitgevoerd. Dit doe je door methodes te schrijven voor elk van de Gegeven, Wanneer, en Dan stappen in de gespecificeerde gherkin scenario's. Hoe dit precies in zijn werk gaat is nader toegelicht met een voorbeeld in deze bron over stap definities.
Cucumber gebruikt speciale annotaties (met de toepasselijke namen @Gegeven, @Wanneer, en @Dan) om te weten welke methode uitgevoerd moet worden voor elke scenario stap. Deze annotaties gebruiken een speciale notatie genaamd Cucumber Expressions om de onderdelen van het Cucumber scenario die testgegevens vertegenwoordigen te onderscheiden. We noemen dit vaak glue code, omdat het de tekst in de scenario stappen bindt aan daadwerkelijke testautomatisering of applicatiecode.
Voor de volledige documentatie over Cucumber Expression zie deze github repository.
:::
Intellij ondersteunt niet meer standaard Cucumber, installeer daarom deze Cucumber plugin: 'Cucumber Java'.
Open de bowling applicatie met Intellij als Maven project <jouw repo van week 5>/oefeningen/les3/voorbereiding/bowling>.
Genereer de method signatures in <./src/test/java/StepDefinitions.java> met Intellij en de Cucumber plugin, zie deze link voor meer informatie.
De method signatures worden meestal automatisch met java8 lambdas gegenereert, mocht je dat ingewikkeld vinden zie deze bron over stap definities om te leren hoe je dit eenvoudig naar simpele functies kunt veranderen.
:::
2.1. implementeren van de glue code
Een Gherkin scenario bestaat altijd uit drie onderdelen die te vergelijken zijn met de 3 A methode voor unit testen die jullie kennen.
- Arrange == Gegeven
- Act == Wanneer
- Assert == Dan
Bij het opstellen van de glue code kunnen we dit in gedachten houden, dus bijvoorbeeld voor deze unit test:
public class GlazenbolTest {
@Test
public void schepBol() {
//Assert
GlazenBol bol = new GlazenBol(1);
bol.verzamelAlleBallen();
//Act
Lottobal lottobal = bol.schepBal();
//Arrange
assertEquals(1, lottobal.balnummer());
}
}
Zou je dit scenario kunnen schrijven:
Scenario: scheppen bal
Gegeven een glazenbol met een capaciteit van 1
Wanneer een bal geschept wordt
Dan zou het balnummer 1 moeten zijn
Met daarbij deze glue code om daar invulling aan te geven:
public class StepDefinitions {
private GlazenBol bol;
private Lottobal geschepteBal;
@Gegeven("een glazenbol met een capaciteit van {int}")
public void eenGlazenbolMetEenCapaciteitVan(int capaciteit) {
bol = new GlazenBol(1);
bol.verzamelAlleBallen();
}
@Wanneer("een bal geschept wordt")
public void eenBalGescheptWordt() {
Lottobal geschepteBal = bol.schepBal();
}
@Dan("zou het balnummer {int} moeten zijn")
public void zouHetBalnummerMoetenZijn(int balnummer) {
assertEquals(nummer, geschepteBal);
}
}
Gezamenlijk geeft dit een uitvoerbare specificatie (test).
2.2. uitvoeren van feature / scenario
✏️ Bekijk de test runner klasse die bij het bowling project zit <jouw repo van week 5>/weekopdracht/jouw-uitwerking/bowling/src/test/java/RunCucumberTest.java>.
Deze Junit5 test suite is geconfigureerd om alle bestanden in de features map uit te voeren met cucumber en ziet er als volgt uit:
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
public class RunCucumberTest {
}
In de toekomst zou je hier wat meer opties aan kunnen toevoegen, maar voor nu voldoet dit prima.
Test de testrunner maar eens door met de rechtermuisknop hierop te drukken in het maven project en te kiezen voor testen runnen.
3. Oefening met het implementeren van de glue code
Maak de glue code om het scoresysteem te kunnen testen van de gegeven bowling game.
✏️ Verdere instructies en casus informatie zijn hier te vinden <jouw repo van week 5>/weekopdracht/jouw-uitwerking/README.md>.
BDD-beoefenaars beginnen graag met het resultaat dat ze moeten verkrijgen en werken dan terug. Begin daarvoor met de @Dan stap, die de uitkomst uitdrukt die verwacht wordt. Wanneer we weten wat er verandert moet zijn als het scenario is uitgevoerd kunnen we bepalen wat er moet gebeuren om dat te bereiken, de @Wanneer stap. Beginnend natuurlijk met de uitgangssituatie, wat is er al voordat het scenario uitgevoerd zal worden, de @Gegeven stap.
Het schrijven van de glue code geeft de perfecte gelegenheid om te experimenteren met verschillende oplossingsrichtingen en te kijken wat het beste bevalt. Bij de bowling game is de implementatie al gegeven dus zijn er geen verschillende oplossingsrichtingen om te onderzoeken.
:::
Bronnen
- Smart J.F. (2014). BDD In Action. Manning. https://www.manning.com/books/bdd-in-action