Les 3-2 BDD

Huiswerk/opdracht

a. Bestudeer de theorie over Behaviour Driven Development zodat je theorie achter de BDD leerdoelen van deze week haalt. De keuze is afhankelijk van of je Java of .NET hebt gekozen in je weekopdracht:

  1. Bestudeer het materiaal van de 'Cucumber' (Java)
  2. Of SpecFlow (.NET) ReqNRoll (.NET) frameworks.

Edit 2024: De praktijk opdracht van BDD is in 2024 optioneel vanwege problemen overgang SpecFlow naar ReqNRoll en dat de 'Dare2Date' casus pas in week 4 volgt. De theorie van BDD moet je uiteraard wel kennen. Je zult de theorie dan in het Beroepsproduct van week 6&7 en het grote project moeten toepassen.

b. Opdrachten (maak tot en met opdracht 4, de rest in de les):

  1. Pak uit de Opdracht voor de DevWorkshop de EuroCard service, maak hier (eigen keuze) een Java of .NET project voor aan, voeg BDD dependencies en tools toe (zie PluralSight) en voeg volgens BDD stijl Cucumber of Specflow tests toe en realiseer zo test-first de methoden.
  2. Installeer hiervoor IntelliJ als je deze nog niet hebt/had (jaar gratis Ultimate editie voor HAN/AIM studenten) of Microsoft Visual Studio
  3. Schrijf Gherkin code (given, when, then) voor 4 testgevallen credit cards nummers: 1, 2, 1023 en 208724
  4. Schrijf glue code ('Step definitions')
  5. Refactor de 4 tests naar één enkele Gherkin 'datatable'
  6. Schrijf evt. ook dezelfde tests in TDD stijl (JUnit/XUnit).
  7. Moet er nog een validatie en aparte melding bij voor credit card nummers met ongeldig format? (eigenlijk zouden ze zo moeten zijn: 6703 4444 4444 4449 (bron) en zou je ook een 'issuer check` kunnen doen).
  8. Waarom wel, of waarom niet? En zo ja, hoe documenteer je dit? (want het staat niet in huidige spec)

Lesprogramma / Lesmateriaal

  • Doornemen leerdoelen high level
  • Behandelen theorie
  • Beantwoorden vragen n.a.v. huiswerk en lesvragen
  • Zelf verder aan de slag met BDD (optioneel in 2024)

Les inhoud / BDD Theorie

Hier wat korte theorie over BDD uit verschillende bronnen, namelijk over de relatie met TDD en DDD uit de Wikipedia definitie, iets over de Three Amigo's (wie) en het 3-staps proces +1 (hoe). Tot slot iets over verschillende namen BDD, ATDD en SBE en quotes van Martin Fowler en Dave Farley.

BDD definitie en relatie met andere *DD's

We beginnen met de definitie van BDD op Wikipedia (2023):

"In software engineering, behavior-driven development (BDD) is a software development process that goes well with Agile software development process that encourages collaboration among developers, quality assurance experts, and customer representatives in a software project. It encourages teams to use conversation and concrete examples to formalize a shared understanding of how the application should behave.

[...] Behavior-driven development combines:

  • the general techniques and principles of TDD
  • with ideas from domain-driven design (DDD)
  • and object-oriented analysis and design

to provide software development and management teams with shared tools and a shared process to collaborate on software development."

BDD's relatie met andere *DD's: Ook test driven en testen 'inherente complexiteit'

Een belangrijk basisbegrip is 'self testing code'. Het is altijd goed het origine artikel van Martin Fowler hierover te lezen. Zijn onderstaande plaatje vat dit kort samen met beeld van code 'met een knop' die zichzelf kan testen. Maar dit kan een onervaren ICT'er onterecht het beeld geven dat je code kunt maken die op een of andere magische wijze zichzelf test (met een tool ofzo). En dat is natuurlijk niet het geval.

Figuur 1: Self testing code (Fowler, 2014)
Figuur 1: Self testing code (Fowler, 2014)

Een iets uitgebreidere samenvatting van 'self testing code' is dat je deze 'knop' realiseert door in een code naast de applicatiecode ook test code op te nemen. Deze test code roept de applicatiecode aan, en controleert dat deze de verwachte output krijgt. Hierbij is ook het doel dat er een hoge 'code coverage' haalt, typisch een line coverage van 80% in onze opleiding. Maar de afspraak hierover verschilt per bedrijf, en is ook afhankelijk van de complexiteit van de codebase (die - bij DDD aanpak - als het goed is vooral afhangt van de complexiteit van het onderliggende domein...). De vereiste code coverage hangt ook af of de codebase een monoliet is, of een microservices architectuur (MSA) heeft. Bij die laatste krijgen integratie testen meer belang en unit tests wat minder, en is code coverage minder van belang (want bij integratie tests is het geautomatiseerd bepalen van code coverage onmogelijk, of in ieder geval ingewikkelder/nog niet standaard).

Hoe dan ook, de interne werking is dus:

digraph G { rankdir=LR; // This sets the direction from left to right subgraph cluster_SelfTesting { label = "Self-Testing System"; A [label="Test code"]; B [label="Application code"]; A -> B; } }

Figuur 2: Intern onderscheid tussen test code (grote O 1) en (vangt de 'inherente' complexiteit conform DDD)

Net als TDD gaat BDD een stap verder dan enkel 'self testing code', want BDD is ook 'test driven'. Door eerst de test code te schrijven, denk je meteen vanuit 'client' kant aan welke interface je methode moet hebben, hoe je deze aanroept, en wat deze teruggeeft. Deze 'HOE roep ik het aan?' zit meer aan de WAT kant: "WAT is de interface", omdat de echte 'hoe' kant is: 'Hoe implementeer ik de code zodat deze daadwerkelijk het verwachte resultaat' teruggeeft. TDD grondlegger Kent Beck (van het Agile Manifesto) noemt dit in zijn article 'Canon-TDD' (2022) de 'Interface/Implementation Split':

"The first misunderstanding is that folks seem to lump all design together. There are two flavors:

  1. How a particular piece of behavior is invoked.
  2. How the system implements that behavior."

BDD -> Geen unit maar integratie tests!

Laten we in de nieuwe 'AI age' waar we in lijken te zitten, sinds de (hype rondom) de introductie van ChatGPT

Me: Wat voor soort testen doe je bij behaviour driven development (BDD)? Kun je deze kort samenvatten in Jip en Janneke taal!?

ChatGPT: Bij Behavior-Driven Development (BDD) worden verschillende soorten testen gebruikt om softwaregedrag te specificeren en te valideren:

  • Acceptatietesten: Test of de software doet wat de baas wil.
  • Scenario's: Verhalen schrijven over hoe de software moet werken.
  • Unit-tests: Kleine stukjes code testen om te zien of ze goed werken.
  • Integratietests: Controleren of alle stukjes samenwerken zonder problemen.
  • Automatisering: Tests laten de computer uitvoeren om tijd te besparen.
  • Regression Testing: Kijken of nieuwe veranderingen geen oude fouten veroorzaken.
De test pyramid - headspin

Figuur 3: De test pyramide (Bron: headspin.io - Open commons licentie)

ChatGPT geeft een mooi overzicht van verschillende soorten tests, die je als developer moet kennen. Maar om unit tests op te nemen in dit overzicht van voor BDD relevante testen is wel een fout van ChatGPT (terzijde: AI modellen/systemen laten zich helaas NIET goed unit testen vanwege hun non-deterministische gedrag). Dus daarom is dit doorgestreept. Want BDD richt zich dus op juist op integratietests of zelfs end-to-end tests (integratie tests over alle lagen/units/functionaliteit heen). Lees bv. op de Cucumber Blog website (z.d.), dat je Cucumber gebruikt voor integratie en end-to-end tests, en NIET voor unit tests:

"BDD should also be used to verify the wanted behaviour using integration tests.

[...] These unit tests will not be validated by a stakeholder as they are written in code, and most stakeholders don't read code. If they did we wouldn't need tools like Cucumber."

De regressie tests die ChatGPT vermeld zijn GEEN wezenlijk verschillende tests van de andere tests die hij eerder noemt. Want je gebruikt je unit-tests en integratie-tests ook als 'regressie tests' om eventuele regressie fouten op te sporen en/of uit te sluiten. Regressiefouten zijn fouten uit stukjes code die 'omvallen' als je later wijzigingen aanbrengt in andere delen van de code waarvan je denkt dat die ongerelateerd zijn, maar die toch aan elkaar gekoppeld blijken (te weinig 'loos coupling').

Je moet de kracht en bedoeling van de verschillende tests kennen:

  • Het voordeel van een unit test boven een acceptatietest is dat deze duidelijker aanwijst waar de fout vandaan komt (namelijk 1 specifieke unit).
  • Het nadeel van units apart is dat deze soms geen fouten aantonen gaan, maar dat er alsnog integratie errors tussen de units buiten beeld blijft, die een acceptatie test wel aanwijst.
  • Het voordeel van een integratie test is dat deze die fout wel laat zien
  • Net nadeel van een integratie test is dat deze een fout niet aanweijzen
  • En een nadeel is dat deze langzamer zijn, om dat bv. echt de database gebruikt word. Bij een unit test moet je externe dependencies/systemen als database altijd mocken

The Three Amigo's

Figuur 1: The three amigo's en het BDD proces met 3 stappen+1(van Pluralsight)

"The 'Three Amigos' is a meeting that takes user stories and turns them into clean, thorough Gherkin scenarios. It involves three voices (at least):

  • The product owner
  • The tester
  • The developer

https://johnfergusonsmart.com/wp-content/uploads/2017/11/iStock-147318638-1024x683.jpg

Figuur 2: The three amigo's, niet per se 3, niet per se Spaans, maar wel per se >=3, divers en onderling vriendschappelijke omgang :)

BDD: 'Executable specifications' en synonieme acro's voor BDD

Gherkin is the most commonly used plain-text language for writing executable specifications in Given-When-Then-And-But steps. These scenarios are commonly saved as .feature files.

Feature: Users should be able to book appointments.

Scenario: A user wants to book an appointment.

Given a user has booked an appointment

When the booking status is timed out

Then the appointment will be not confirmed

Bron: 'What are executable specifications?' - Cucumber.io blog, 7-2-2019

... "BDD aims to express requirements unambiguously, not simply create tests. The result may be viewed as an expression of requirements or a test, but the result is the same. Acceptance tests record the decisions made in the conversation between the team and the Product Owner so that the team understands the intended behavior.

There are three alternative labels to this detailing process:

  • Behavior Driven Design (BDD)
  • Acceptance Test–Driven Development (ATDD)
  • Specification by Example (SBE)

Bron & ©: Scaled Agile, Inc.

Lesvragen

Behandelen opgekomen studentenvragen n.a.v. huiswerk of behandelde theorie. Als er geen vragen zijn, dan staan we even stil bij deze vragen:

  1. Kun je in algemeen zowel TDD als BDD doen in een project, of moet je kiezen?
  2. Welke CDMM checkpunten zijn relevant voor BDD?
  3. Voor Java is er Cucumber, voor .NET is erSpecFlow of ReqNRoll, maar welke taal gebruik je wel in beide voor BDD?
  4. Wat is een test suit? Heeft een applicatie een testsuite?
  5. Het Gherkin voorbeeld op de pagina toont één feature met één scenario. Is dit typisch, of horen bij één feature vaak meer scenario's, of bij één scenario meerdere features?

Quiz

Check je kennis over BDD met onderstaande korte multiple choice toets.

Leerdoelen

Check met onderstaande leerdoelen of je de behandelde stof begrepen hebt en toetsvragen kunt beantwoorden.

  • Je kent de relatie van BDD met TDD, DDD en Agile/DevOps
    • met o.a. relevante begrippen als Ubiquitous Language, test-first, red-green-refactor, AAA pattern, given-when-then en collaborative development
  • Je kent de BDD three amigo's, en de 3 stappen van het iteratieve BDD proces
  • Je kent 2 andere namen van BDD, en kunt deze uitleggen
  • Je kent de term 'self testing code' en het onderscheid tussen .feature files, glue code en applicatie code en de talen/standaarden die hier achterin zitten
  • Je kunt de verhouding uitleggen tussen BDD test scenario's, test cases en suites met user stories en acceptatiecriteria uit Scrum
  • Je kent de test pyramide, het belang van de verschillende soorten testen hierin en de link met BDD
  • Je kunt op basis van een tutorial een project met werkende en relevante BDD tests opstellen m.b.v. Cucumber of Specflow (ReqNRoll)

Bronnen

Last change: 2025-01-13