TDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt

  1. Home
  2. Blog
  3. Testautomatisering

Testautomatisering

TDD versus BDD: Belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt

TDD helpt ontwikkelaars bij het ontwerpen van correcte code. BDD helpt een heel team het eens te worden over wat de software moet doen. Bekijk dezelfde kortingsfunctie die bij elke aanpak is toegepast en leer hoe deze twee samenwerken.

9 min leestijd
TDD versus BDD: belangrijkste verschillen, één functie die in beide richtingen is gebouwd en wanneer deze moet worden gebruikt

Belangrijkste punten

  • TDD betekent dat je eerst een mislukte test schrijft, dan net genoeg code om te slagen en dan opruimt.
  • BDD beschrijft gedrag in gedeelde taal, meestal als Gegeven, Wanneer, Dan.
  • TDD begeleidt voornamelijk het codeontwerp. BDD bouwt vooral aan gedeeld begrip.
  • Ze zijn geen rivalen en veel teams gebruiken BDD voor functies en TDD voor de onderstaande details.

Het debat TDD versus BDD wordt vaak voorgesteld als het kiezen van een kant. In werkelijkheid beantwoorden ze verschillende vragen. Bij testgedreven ontwikkeling wordt gevraagd of de code doet wat de ontwikkelaar bedoelde, terwijl bij gedragsgedreven ontwikkeling wordt gevraagd of het team het überhaupt eens is over wat de software moet doen.

Om het verschil concreet te maken, bouwen we bij elke aanpak één kleine kortingsfunctie. We hebben de code uitgevoerd op Python 3.13, met behulp van de standaardbibliotheek, en de onderstaande resultaten komen uit die run. Het BDD-gedeelte gebruikt een eigen klein lopertje om het mechanisme te laten zien, dus een echt project zou een hulpmiddel zoals Komkommer gebruiken of zich in plaats daarvan gedragen.

Het korte antwoord

Testgestuurde ontwikkeling (TDD) is een codeerpraktijk. Je schrijft een kleine mislukte test, zorgt ervoor dat deze slaagt met de eenvoudigste code en verbetert vervolgens het ontwerp. Tests worden in code geschreven, en voornamelijk door ontwikkelaars. Kent Beck maakte de praktijk populair.

Gedragsgestuurde ontwikkeling (BDD) is een samenwerkingspraktijk die is voortgekomen uit TDD, en Dan North introduceerde de term. Ontwikkelaars, testers en zakenmensen zijn het eens over voorbeelden van hoe het systeem zich zou moeten gedragen, geschreven in duidelijke taal, en die voorbeelden kunnen vervolgens worden geautomatiseerd.

TDD versus BDD naast elkaar

Aspect TDD BDD
Hoofdfocus Correcte, goed ontworpen code Gedeeld begrip van gedrag
Ingeschreven Programmeertaal Duidelijke taal, zoals augurk
Geschreven door Ontwikkelaars Business, QA en ontwikkelaars samen
Leesbaar door Ontwikkelaars Iedereen in het team
Typisch niveau Eenheid Kenmerk of acceptatie
Uitgangspunt Een mislukte proef Een gesprek met voorbeelden
Cyclus Rood, groen, refactor Ontdek, formuleer, automatiseer
Gemeenschappelijke hulpmiddelen pytest, JUnit, Jest Komkommer, gedragen, SpecFlow, Reqnroll

De functie

Dit is de bedrijfsregel die we zullen implementeren: Bestellingen van 1000 of meer krijgen 10% korting. Leden krijgen 5% extra korting op deze bestellingen.

Dat klinkt misschien helder, maar het is al dubbelzinnig. Krijgt een lid dat 500 euro besteedt, 5% korting? In de zin staat ‘die bevelen’, dus we gaan ervan uit van niet. Houd dat in gedachten, want dit is precies het soort vraag dat BDD in een vroeg stadium naar voren wil brengen.

Bouw het met TDD

TDD volgt een korte lus die bekend staat als rood, groen, refactor:

Stap Wat je doet
Rood Schrijf één test voor gedrag dat nog niet bestaat, en zie hoe het mislukt
Groen Schrijf de eenvoudigste code die ervoor zorgt dat het lukt
Refactor Verbeter de code en houd de tests groen

Dit zijn onze tests, met één voor elke regel:

class DiscountTests(unittest.TestCase):
    def test_no_discount_below_1000(self):
        self.assertEqual(discount(999, False), 0)

    def test_ten_percent_from_1000(self):
        self.assertEqual(discount(1000, False), 100)

    def test_member_gets_extra_five_percent(self):
        self.assertEqual(discount(1000, True), 150)

Vervolgens hebben we de code in drie fasen geschreven, waarbij we na elke fase de tests hebben uitgevoerd. Een strikte TDD-sessie voegt één test tegelijk toe, en dit laat dezelfde progressie zien:

Fase 1: het eenvoudigste

def discount(total, is_member):
    return 0

# 3 tests, 2 failed
#   test_member_gets_extra_five_percent
#   test_ten_percent_from_1000

Het retourneren van nul ziet er raar uit, maar het bewijst dat de tests daadwerkelijk kunnen mislukken, en de enige test die het doorstaat is de ‘geen korting’-regel.

Fase 2: voeg de drempel toe

def discount(total, is_member):
    if total >= 1000:
        return total * 0.1
    return 0

# 3 tests, 1 failed
#   test_member_gets_extra_five_percent

Fase 3: leden toevoegen en opruimen

def discount(total, is_member):
    rate = 0.1 if total >= 1000 else 0
    if is_member:
        rate += 0.05
    return round(total * rate, 2)

# 3 tests, 0 failed

Alle drie passeren. Maar lees deze versie aandachtig. Het geeft een lid dat 500 euro besteedt een korting van 5%, wat niet is wat we dachten dat de regel betekende. Geen enkele test heeft dat geval gedekt, dus niets heeft dit gemarkeerd. TDD beschermt alleen het gedrag dat je dacht te testen. Dat is een echte beperking, en de reden waarom gesprekken over voorbeelden zo belangrijk zijn.

Waarom de cyclus ertoe doet

  • Rood bewijst dat de test werkt. Een test die nooit heeft gefaald, test misschien niets.
  • Groen houdt je gefocust. Je schrijft alleen de code die nodig is, waardoor over-engineering wordt voorkomen.
  • Refactor houdt de kwaliteit hoog. Tests geven u het vertrouwen om het ontwerp veilig te wijzigen.
  • Het heeft invloed op het ontwerp. Moeilijk te testen code is vaak te nauw met elkaar verbonden, en dat merk je meteen.

Onze pytest-tutorial laat een gemakkelijkere manier zien om dit soort tests te schrijven, en grenswaardeanalyse legt uit waarom we 999 en 1000 als waarden hebben gekozen.

Bouw het met BDD

BDD begint met een gesprek, niet met hulpmiddelen. Vaak is het een korte bijeenkomst die bekend staat als de drie amigo’s, waarbij een productpersoon, een ontwikkelaar en een tester concrete voorbeelden bespreken:

Tester:  What about a member spending 500?
Product: Good question. No discount. It has to reach 1000 first.
Dev:     And exactly 1000 counts?
Product: Yes, 1000 or more.

Die ene uitwisseling zou het probleem in onze TDD-code hebben opgevangen. Vervolgens nemen ze hun voorbeelden op in een gestructureerd formaat genaamd Gherkin:

Feature: Order discounts

  Scenario: Member reaches the discount threshold
    Given a member with a cart worth 1000
    When they view the amount to pay
    Then the amount to pay is 850

  Scenario: Member below the threshold gets no discount
    Given a member with a cart worth 500
    When they view the amount to pay
    Then the amount to pay is 500
Trefwoord Doel
Gegeven De uitgangssituatie
Wanneer De actie of gebeurtenis
Dan Het verwachte resultaat

Iedereen in het team kan dat lezen en zeggen ‘ja, dat klopt’ of ‘nee, dat klopt’. Zelfs als je het nooit automatiseert, heeft het scenario al nuttig werk verricht.

Stappen verbinden met code

Tools verbinden elke regel in duidelijke taal met een functie, een zogenaamde stapdefinitie. Om het idee te laten zien, hebben we zelf een kleine versie geschreven en het eerste scenario uitgevoerd:

@step("a member with a cart worth 1000")
def given(ctx):
    ctx["cart"] = Cart(is_member=True)
    ctx["cart"].add(1000)

@step("they view the amount to pay")
def when(ctx):
    ctx["amount"] = ctx["cart"].payable()

@step("the amount to pay is 850")
def then(ctx):
    assert ctx["amount"] == 850

# ok Given a member with a cart worth 1000
# ok When they view the amount to pay
# ok Then the amount to pay is 850

Echte tools voegen parameters toe, zodat een enkele stap zowel “1000” als “500” kan matchen, plus rapportage. Het resultaat is levende documentatie: een duidelijke beschrijving van het systeem, die luid faalt als het niet meer waar is.

Tip: De waarde van BDD ligt in het gesprek. Teams waarbij één persoon Gherkin alleen schrijft nadat de code is voltooid, krijgen de kosten van de tool, maar vrijwel niets van de voordelen.

Goede scenario’s schrijven

Zwak Beter
Wanneer ik op de knop met id "btn-77" klik Wanneer ik de coupon toepas
Dan klopt de uitslag Dan bedraagt het te betalen bedrag 850
Twintig stappen in één scenario Eén gedrag per scenario
Beschrijft het scherm Beschrijft de zakelijke bedoeling

Scenario’s die klikken en veld-ID’s beschrijven, breken bij elk nieuw ontwerp en zakelijke lezers lezen ze niet meer. Bewaar de details van de gebruikersinterface in de stapcode. Deze scenario’s zijn nauw verwant aan de voorbeelden in testcase versus testscenario, en worden ook vaak gebruikt bij gebruikersacceptatietests.

Beide samen gebruiken

De twee passen op natuurlijke wijze in een ‘outside-in’-workflow:

  1. Het team maakt afspraken over het gedrag en schrijft een BDD-scenario. Het mislukt, omdat er nog niets bestaat.
  2. Een ontwikkelaar gebruikt TDD om de benodigde kleine eenheden te bouwen.
  3. Unit-tests slagen, en uiteindelijk ook het scenario.
  4. Alles draait in uw CI/CD-pijplijn.

Houd ze allemaal op het juiste niveau. Je zou een paar scenario’s moeten hebben voor belangrijk gedrag, en veel snelle unit-tests voor de details. Onze gids voor unit- versus integratietests behandelt de balans.

Gereedschap

Taal TDD (eenheidstesten) BDD
Python pytest, unittest gedragen, pytest-bdd
JavaScript Gek, Vitest Cucumber.js
Java JUnit, TestNG Komkommer-JVM
.NET xEenheid, NUeenheid Reqnroll, SpecFlow

Wanneer moet u ze allemaal gebruiken?

TDD past goed wanneer:

  • U schrijft complexe logica, zoals prijzen, parseren of machtigingen.
  • Je repareert een bug, omdat je deze eerst kunt reproduceren met een mislukte test.
  • Je werkt aan code die vaak zal veranderen.

BDD past goed wanneer:

  • Bedrijfsregels zijn complex en misverstanden zijn duur.
  • Niet-technische mensen zullen de scenario’s echt lezen en bespreken.
  • Verschillende teams hebben behoefte aan een gedeelde definitie van hoe iets zich gedraagt.

Het kan overdreven zijn als je: een wegwerpprototype schrijft of een onduidelijk technisch idee onderzoekt. Veel ontwikkelaars pieken eerst en herschrijven vervolgens met tests. BDD-tooling is ook een slechte investering als niemand buiten de engineering ooit naar de scenario’s zal kijken. In dat geval zijn eenvoudige tests met goede namen eenvoudiger.

Veel voorkomende fouten

  • BDD behandelen als een testtool. Komkommer zonder samenwerking is slechts een uitgebreide manier om tests te schrijven.
  • Implementatie testen in TDD. Tests die verband houden met privégegevens breken tijdens elke refactor.
  • De refactorstap wordt overgeslagen. Je slaagt voor tests naast rommelige code.
  • Tests achter de code schrijven en deze TDD noemen. Dat is nog steeds nuttig, maar je verliest de ontwerpfeedback.
  • Te veel UI-scenario’s schrijven. Deze worden traag en onstabiel. Zie flaky-tests.
  • Op jacht naar dekkingscijfers. Goede berichtgeving mist nog steeds gedrag waar niemand rekening mee heeft gehouden, zoals uit ons voorbeeld blijkt.

Tot slot

TDD helpt je om het juiste te bouwen, en BDD helpt je om het juiste te bouwen. Ons kortingsvoorbeeld liet beide kanten zien: de code doorstond alle tests, maar een eenvoudig gesprek bracht een verkeerde veronderstelling aan het licht. Probeer het op uw volgende kleine functie. Schrijf samen met een collega drie concrete voorbeelden vóór elke code, en bouw deze vervolgens één mislukte test tegelijk.

Veelgestelde vragen

Wat is het belangrijkste verschil tussen TDD en BDD?

TDD richt zich op ontwikkelaars die falende codetests schrijven vóór implementatie. BDD richt zich erop dat een heel team het eens wordt over gedrag aan de hand van voorbeelden in duidelijke taal.

Kun je TDD en BDD samen gebruiken?

Ja, en veel teams doen dat ook. BDD-scenario’s definiëren functies van buitenaf, en TDD stuurt de kleinere code-eenheden eronder aan.

Is BDD beter dan TDD?

Geen van beide is in het algemeen beter, omdat ze verschillende problemen oplossen. BDD helpt bij gedeeld begrip, en TDD helpt bij codeontwerp en snelle feedback.

Wat is augurk?

Augurk is een gestructureerd formaat in eenvoudige taal voor het schrijven van scenario’s, met behulp van trefwoorden als Gegeven, Wanneer en Dan. Tools zoals Cucumber kunnen het uitvoeren.

Vertraagt ​​TDD de ontwikkeling?

In het begin kan het langzamer aanvoelen, vooral tijdens het leren. Teams winnen vaak tijd terug door minder bugs en veiligere wijzigingen, hoewel het effect per project verschilt.

Blijf leren

Werk met Stack Quora

Hulp nodig met testen, WordPress of SEO?

We helpen teams betere software te leveren en hun sites te laten groeien. Vertel ons waar u mee bezig bent en wij stellen een duidelijke volgende stap voor.

Blijf lezen

Meer handleidingen over testen, AI en moderne ontwikkeling

Genoten van dit artikel? Kies een onderwerp en ga direct naar onze nieuwste tutorials.

Kunstmatige intelligentie

AI-hallucinaties uitgelegd: waarom taalmodellen dingen verzinnen en hoe ze te verminderen

AI-hallucinaties uitgelegd: wat ze zijn, waarom taalmodellen ze produceren, veelvoorkomende typen, hoe je ze kunt verminderen met aarding en aanwijz…

Lees artikel →
DevOps

Omgevingsvariabelen uitgelegd: .env-bestanden, geheimen en configuratie goed gedaan

Omgevingsvariabelen uitgelegd met Python-voorbeelden die we hebben uitgevoerd: ze lezen en instellen, waarom elke waarde een string is, .env-bestand…

Lees artikel →
Softwareontwikkeling

API-snelheidsbeperking uitgelegd: algoritmen, headers en afhandeling van 429-fouten

API-snelheidsbeperking uitgelegd met een simulatie die we hebben uitgevoerd: token-bucket, vast venster, schuifvenster, 429 reacties, headers van sn…

Lees artikel →
Testautomatisering

Spotten in Python: unittest.mock, patch en de fouten die tests doen liegen

Spotten in Python met unittest.mock, getest: Mock en return_value, side_effect, patchen waar een naam wordt gebruikt, spec en autospec, spotdatums e…

Lees artikel →
Softwaretesten

Codedekking uitgelegd: lijn versus filiaaldekking en wat 100% werkelijk betekent

Codedekking uitgelegd met een echte dekking.py-run: dekking van lijnen, vertakkingen en condities, een rapport lezen, waarom 100% dekking nog steeds…

Lees artikel →
Databases & SQL

DELETE versus TRUNCATE versus DROP in SQL: verschillen, terugdraaien en wanneer elk te gebruiken

DELETE versus TRUNCATE versus DROP uitgelegd met geteste SQL: wat elk verwijdert, terugdraaien, triggers, identiteitsreset, snelheid en hoe PostgreS…

Lees artikel →
Databases & SQL

SQL-weergaven uitgelegd: creëer, gebruik en vermijd de valkuilen, met voorbeelden

SQL-weergaven uitgelegd met query's die we hebben uitgevoerd: een weergave maken, live resultaten, kolommen verbergen, prestaties, bijwerkbare en ge…

Lees artikel →
Softwareontwikkeling

TypeScript-interface versus type: echte verschillen, getest met de compiler

TypeScript-interface versus type, gecontroleerd met de echte compiler: wat beide kunnen doen, wat slechts één kan doen, samenvoegen van declaraties,…

Lees artikel →
Softwareontwikkeling

Python *args en **kwargs uitgelegd: flexibele functies met duidelijke voorbeelden

Python *args en **kwargs uitgelegd met code die we hebben uitgevoerd: in- en uitpakken, parametervolgorde, argumenten die alleen trefwoorden en posi…

Lees artikel →
Softwareontwikkeling

Python Lambda-functies: syntaxis, echt gebruik en wanneer u ze niet moet gebruiken

Python lambda-functies uitgelegd met code die we hebben uitgevoerd: syntaxis, sorteren met sleutel, kaart en filter, sluitingen, de laat-bindende va…

Lees artikel →
Kunstmatige intelligentie

Wat zijn AI-agenten? Hoe ze werken, met een eenvoudige agentloop die u kunt uitvoeren

Wat zijn AI-agenten? Een duidelijke gids voor de agentenlus, tools, geheugen en vangrails, met een kleine Python-lus die we hebben uitgevoerd, echte…

Lees artikel →
DevOps

Monitoring versus waarneembaarheid: het echte verschil, met logboeken, statistieken en sporen

Monitoring versus waarneembaarheid uitgelegd: bekende en onbekende fouten, logboeken, statistieken en sporen, een walkthrough voor afrekenincidenten…

Lees artikel →
DevOps

Docker-volumes versus bindingsmounts: bewaar containergegevens op de juiste manier

Docker-volumes versus bind-mounts uitgelegd: waarom containergegevens verdwijnen, benoemde volumes, bind-mounts, tmpfs, Compose-voorbeelden, back-up…

Lees artikel →
Testautomatisering

TDD versus BDD: belangrijkste verschillen, één functie die op beide manieren is gebouwd en wanneer deze moet worden gebruikt

TDD versus BDD uitgelegd met één kortingsfunctie die in beide richtingen is gebouwd: rood-groen-refactor met code die we hebben uitgevoerd, gegeven-…

Lees artikel →
Softwareontwikkeling

Git merge vs rebase: verschillen, voorbeelden en wanneer je wat gebruikt

Git merge vs rebase uitgelegd met echte logoutput, een vergelijkingstabel, de gouden regel van rebase en een veilige teamwerkwijze.

Lees artikel →
Softwareontwikkeling

Python list comprehension: syntaxis, voorbeelden en wanneer je het vermijdt

Python list comprehension uitgelegd: syntaxis, filteren, if-else, geneste lussen, gemeten tijden en wanneer een gewone for-lus beter is.

Lees artikel →
Databases & SQL

SQL JOIN uitgelegd met voorbeelden (Inner, Left, Right, Full)

Begrijp SQL joins stap voor stap met voorbeeldtabellen en queries: INNER, LEFT, RIGHT, FULL, CROSS en SELF, plus veelgemaakte fouten en prestatietips.

Lees artikel →