TDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte

  1. Startseite
  2. Blog
  3. Testautomatisierung

Testautomatisierung

TDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann man sie jeweils verwendet

TDD hilft Entwicklern, korrekten Code zu entwerfen. BDD hilft einem ganzen Team, sich darauf zu einigen, was die Software tun soll. Sehen Sie sich die gleiche Rabattfunktion an, die bei jedem Ansatz integriert ist, und erfahren Sie, wie die beiden zusammenarbeiten.

9 Min. Lesezeit
TDD vs. BDD: Hauptunterschiede, eine Funktion, die in beide Richtungen erstellt wurde und wann sie jeweils verwendet werden sollte

Das Wichtigste

  • TDD bedeutet, zuerst einen fehlgeschlagenen Test zu schreiben, dann gerade genug Code zum Bestehen zu schreiben und dann aufzuräumen.
  • BDD beschreibt Verhalten in einer gemeinsamen Sprache, normalerweise als Gegeben, Wann, Dann.
  • TDD leitet hauptsächlich das Code-Design. BDD baut hauptsächlich ein gemeinsames Verständnis auf.
  • Sie sind keine Rivalen und viele Teams verwenden BDD für Funktionen und TDD für die unten aufgeführten Details.

Die Debatte TDD vs. BDD wird oft als die Wahl einer Seite dargestellt. In Wirklichkeit beantworten sie unterschiedliche Fragen. Bei der testgetriebenen Entwicklung wird gefragt, ob der Code das tut, was der Entwickler beabsichtigt hat, während bei der verhaltensgesteuerten Entwicklung gefragt wird, ob das Team sich darüber einig ist, was die Software überhaupt tun soll.

Um den Unterschied konkret zu machen, bauen wir bei jedem Ansatz eine kleine Rabattfunktion ein. Wir haben den Code unter Verwendung der Standardbibliothek auf Python 3.13 ausgeführt und die folgenden Ergebnisse stammen aus diesem Lauf. Der BDD-Teil verwendet einen kleinen eigenen Läufer, um den Mechanismus zu zeigen, sodass ein echtes Projekt stattdessen ein Tool wie Cucumber oder behave verwenden würde.

Die kurze Antwort

Testgetriebene Entwicklung (TDD) ist eine Codierungspraxis. Sie schreiben einen kleinen fehlgeschlagenen Test, sorgen dafür, dass er mit dem einfachsten Code besteht, und verbessern dann das Design. Tests werden in Code geschrieben und hauptsächlich von Entwicklern. Kent Beck machte diese Praxis populär.

Behaviour-driven Development (BDD) ist eine Praxis der Zusammenarbeit, die aus TDD hervorgegangen ist, und Dan North hat den Begriff eingeführt. Entwickler, Tester und Geschäftsleute einigen sich auf Beispiele dafür, wie sich das System verhalten soll, geschrieben in einfacher Sprache, und diese Beispiele können dann automatisiert werden.

TDD vs. BDD nebeneinander

Aspekt TDD BDD
Hauptaugenmerk Korrekter, gut gestalteter Code Geteiltes Verhaltensverständnis
Eingeschrieben Programmiersprache Einfache Sprache, wie zum Beispiel Gherkin
Geschrieben von Entwickler Business, Qualitätssicherung und Entwickler zusammen
Lesbar von Entwickler Jeder im Team
Typisches Niveau Einheit Merkmal oder Akzeptanz
Ausgangspunkt Ein fehlgeschlagener Test Ein Gespräch mit Beispielen
Zyklus Rot, Grün, Refaktor Entdecken, formulieren, automatisieren
Gängige Werkzeuge pytest, JUnit, Jest Gurke, Verhalten, SpecFlow, Reqnroll

Die Funktion

Hier ist die Geschäftsregel, die wir umsetzen werden: Auf Bestellungen ab 1.000 Stück erhalten Sie 10 % Rabatt. Mitglieder erhalten zusätzlich 5 % Rabatt auf diese Bestellungen.

Das mag klar klingen, ist aber bereits zweideutig. Bekommt ein Mitglied, das 500 ausgibt, 5 % Rabatt? Der Satz lautet „diese Befehle“, daher gehen wir davon aus, dass dies nicht der Fall ist. Denken Sie daran, denn das ist genau die Art von Frage, die BDD frühzeitig aufwerfen soll.

Erstellen Sie es mit TDD

TDD folgt einer kurzen Schleife, die als Rot, Grün, Refaktor bekannt ist:

Schritt Was du tust
Rot Schreiben Sie einen Test für ein Verhalten, das noch nicht existiert, und beobachten Sie, wie er fehlschlägt
Grün Schreiben Sie den einfachsten Code, der es zum Erfolg bringt
Umgestalten Verbessern Sie den Code und halten Sie die Tests grün

Dies sind unsere Tests, mit einem für jede 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)

Anschließend haben wir den Code in drei Schritten geschrieben und nach jedem Schritt die Tests ausgeführt. Eine strikte TDD-Sitzung fügt jeweils einen Test hinzu, und dies zeigt den gleichen Fortschritt:

Stufe 1: die einfachste Sache

def discount(total, is_member):
    return 0

# 3 tests, 2 failed
#   test_member_gets_extra_five_percent
#   test_ten_percent_from_1000

Null zurückzugeben sieht albern aus, beweist aber, dass die Tests tatsächlich fehlschlagen können, und der einzige Test, den es besteht, ist die „Kein Rabatt“-Regel.

Stufe 2: Schwellenwert hinzufügen

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

# 3 tests, 1 failed
#   test_member_gets_extra_five_percent

Stufe 3: Mitglieder hinzufügen und aufräumen

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 drei bestehen. Aber lesen Sie diese Version genau durch. Dadurch erhält ein Mitglied, das 500 € ausgibt, einen Rabatt von 5 %, was unserer Meinung nach nicht mit der Regel gemeint ist. Da es keinen Test gab, der diesen Fall abdeckte, gab es keine Hinweise darauf. TDD schützt nur das Verhalten, das Sie testen wollten. Das ist eine echte Einschränkung und der Grund, warum Gespräche über Beispiele so wichtig sind.

Warum der Zyklus wichtig ist

  • Rot beweist, dass der Test funktioniert. Ein Test, der nie fehlgeschlagen ist, testet möglicherweise gar nichts.
  • Green sorgt dafür, dass Sie konzentriert bleiben. Sie schreiben nur den Code, der benötigt wird, was dazu beiträgt, Over-Engineering zu vermeiden.
  • Refactor sorgt für eine hohe Qualität. Tests geben Ihnen die Sicherheit, das Design sicher zu ändern.
  • Es beeinflusst das Design. Code, der schwer zu testen ist, ist oft zu eng gekoppelt, und das merkt man sofort.

Unser Pytest-Tutorial zeigt eine bequemere Möglichkeit, solche Tests zu schreiben, und die Randwertanalyse erklärt, warum wir 999 und 1000 als Werte gewählt haben.

Erstellen Sie es mit BDD

BDD beginnt mit einem Gespräch, nicht mit Werkzeugen. Oftmals handelt es sich um ein kurzes Treffen, das als die drei Freunde bekannt ist und bei dem ein Produktmitarbeiter, ein Entwickler und ein Tester konkrete Beispiele besprechen:

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.

Dieser eine Austausch hätte das Problem in unserem TDD-Code erkannt. Anschließend zeichnen sie ihre Beispiele in einem strukturierten Format namens Gherkin auf:

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
Stichwort Zweck
Gegeben Die Ausgangssituation
Wann Die Aktion oder das Ereignis
Dann Das erwartete Ergebnis

Jeder im Team kann das lesen und sagen „Ja, das ist richtig“ oder „Nein, das ist falsch“. Auch wenn Sie es nie automatisieren, hat das Szenario bereits nützliche Arbeit geleistet.

Schritte mit Code verbinden

Tools verbinden jede Klartextzeile mit einer Funktion, die als Schrittdefinition bezeichnet wird. Um die Idee zu veranschaulichen, haben wir selbst eine kleine Version geschrieben und das erste Szenario ausgeführt:

@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 fügen Parameter hinzu, sodass ein einzelner Schritt sowohl „1000“ als auch „500“ entsprechen kann, plus Berichterstellung. Das Ergebnis ist eine lebendige Dokumentation: eine klare Beschreibung des Systems, die lautstark scheitert, wenn sie nicht mehr wahr ist.

Tipp: Der Wert von BDD liegt im Gespräch. Teams, bei denen eine Person allein Gherkin schreibt, nachdem der Code fertig ist, erhalten die Kosten für das Tool, haben jedoch fast keinen Nutzen davon.

Gute Szenarien schreiben

Schwach Besser
Wenn ich auf die Schaltfläche mit der ID „btn-77“ klicke Wenn ich den Gutschein einlöse
Dann ist das Ergebnis korrekt Dann beträgt der zu zahlende Betrag 850
Zwanzig Schritte in einem Szenario Ein Verhalten pro Szenario
Beschreibt den Bildschirm Beschreibt die Geschäftsabsicht

Szenarien, die Klicks und Feld-IDs beschreiben, brechen bei jeder Neugestaltung ab und werden von Fachlesern nicht mehr gelesen. Behalten Sie die Details der Benutzeroberfläche im Schrittcode bei. Diese Szenarien sind enge Verwandte der Beispiele in Testfall vs. Testszenario und werden häufig auch in Benutzerakzeptanztests verwendet.

Beides zusammen nutzen

Die beiden passen natürlich in einen „Outside-In“-Workflow:

  1. Das Team einigt sich auf das Verhalten und schreibt ein BDD-Szenario. Es schlägt fehl, weil noch nichts existiert.
  2. Ein Entwickler verwendet TDD, um die benötigten kleinen Einheiten zu erstellen.
  3. Unit-Tests werden bestanden, und schließlich auch das Szenario.
  4. Alles läuft in Ihrer CI/CD-Pipeline.

Halten Sie jeweils das richtige Niveau. Sie sollten über einige Szenarien für wichtige Verhaltensweisen und viele schnelle Komponententests für die Details verfügen. Unser Leitfaden zu Einheits- und Integrationstests deckt die Balance ab.

Werkzeuge

Sprache TDD (Unit-Test) BDD
Python Pytest, Unittest benimm dich, pytest-bdd
JavaScript Scherz, Vitest Cucumber.js
Java JUnit, TestNG Gurken-JVM
.NET xUnit, NUnit Reqnroll, SpecFlow

Wann jeweils zu verwenden ist

TDD passt gut, wenn:

  • Sie schreiben komplexe Logik wie Preise, Parsing oder Berechtigungen.
  • Sie beheben einen Fehler, da Sie ihn zunächst mit einem fehlgeschlagenen Test reproduzieren können.
  • Sie arbeiten an Code, der sich häufig ändert.

BDD passt gut, wenn:

  • Geschäftsregeln sind komplex und Missverständnisse teuer.
  • Nicht-technische Leute werden die Szenarien wirklich lesen und diskutieren.
  • Mehrere Teams benötigen eine gemeinsame Definition, wie sich etwas verhält.

Beides kann übertrieben sein, wenn: Sie einen Wegwerf-Prototyp schreiben oder eine unklare technische Idee untersuchen. Viele Entwickler führen zunächst einen Spike durch und schreiben dann mit Tests neu. BDD-Werkzeuge sind auch eine schlechte Investition, wenn sich niemand außerhalb des Ingenieurwesens jemals mit den Szenarien befasst. In diesem Fall sind einfache Tests mit guten Namen einfacher.

Häufige Fehler

  • BDD als Testtool behandeln. Cucumber ohne Zusammenarbeit ist nur eine ausführliche Art, Tests zu schreiben.
  • Testen der Implementierung in TDD. Tests, die an private Details gebunden sind, brechen bei jedem Refactoring ab.
  • Sie überspringen den Refactoring-Schritt. Sie bestehen Tests zusätzlich zu unordentlichem Code.
  • Tests nach dem Code schreiben und ihn TDD nennen. Das ist immer noch nützlich, aber Sie verlieren das Design-Feedback.
  • Schreiben zu vieler UI-Szenarien. Diese werden langsam und flockig. Siehe Flockentests.
  • Auf der Jagd nach Berichterstattungszahlen. Eine gute Berichterstattung übersieht immer noch Verhaltensweisen, die niemand berücksichtigt hat, wie unser Beispiel zeigt.

Fazit

TDD hilft Ihnen, das Richtige zu bauen, und BDD hilft Ihnen, das Richtige zu bauen. Unser Rabattbeispiel zeigte beide Seiten: Der Code hat alle Tests bestanden, doch ein einfaches Gespräch offenbarte eine falsche Annahme. Probieren Sie es bei Ihrem nächsten kleinen Feature aus. Schreiben Sie vor jedem Code drei konkrete Beispiele mit einem Kollegen und erstellen Sie ihn dann für einen fehlgeschlagenen Test nach dem anderen.

Häufige Fragen

Was ist der Hauptunterschied zwischen TDD und BDD?

TDD konzentriert sich auf Entwickler, die vor der Implementierung fehlerhafte Codetests schreiben. BDD konzentriert sich darauf, dass sich ein ganzes Team anhand von Beispielen in einfacher Sprache auf das Verhalten einigt.

Können Sie TDD und BDD zusammen verwenden?

Ja, und das tun viele Teams. BDD-Szenarien definieren Features von außen und TDD steuert die kleineren Codeeinheiten darunter.

Ist BDD besser als TDD?

Keines von beiden ist insgesamt besser, da sie unterschiedliche Probleme lösen. BDD hilft beim gemeinsamen Verständnis und TDD hilft beim Codedesign und schnellem Feedback.

Was ist Gurke?

Gherkin ist ein strukturiertes Klartextformat zum Schreiben von Szenarien, das Schlüsselwörter wie „Given“, „When“ und „Then“ verwendet. Tools wie Cucumber können es ausführen.

Verlangsamt TDD die Entwicklung?

Am Anfang kann es sich langsamer anfühlen, besonders beim Lernen. Durch weniger Fehler und sicherere Änderungen gewinnen Teams oft Zeit zurück, auch wenn der Effekt je nach Projekt unterschiedlich ist.

Lerne weiter

Arbeiten Sie mit Stack Quora

Benötigen Sie Hilfe beim Testen, WordPress oder SEO?

Wir helfen Teams, bessere Software zu liefern und ihre Websites zu erweitern. Sagen Sie uns, woran Sie gerade arbeiten, und wir schlagen Ihnen einen klaren nächsten Schritt vor.

Lesen Sie weiter

Weitere Anleitungen finden Sie unter Tests, KI und moderne Entwicklung

Hat Ihnen dieser Artikel gefallen? Wählen Sie ein Thema und springen Sie direkt in unsere neuesten Tutorials.

Künstliche Intelligenz

KI-Halluzinationen erklärt: Warum Sprachmodelle Dinge erfinden und wie man sie reduziert

KI-Halluzinationen erklärt: Was sie sind, warum Sprachmodelle sie produzieren, gängige Typen, wie man sie mit Erdung und Eingabeaufforderungen reduz…

Artikel lesen →
DevOps

Erklärte Umgebungsvariablen: .env-Dateien, Geheimnisse und Konfiguration richtig gemacht

Umgebungsvariablen anhand von Python-Beispielen erklärt, die wir ausgeführt haben: Sie lesen und festlegen, warum jeder Wert ein String ist, .env-Da…

Artikel lesen →
Softwareentwicklung

API-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern

API-Ratenbegrenzung anhand einer von uns durchgeführten Simulation erklärt: Token-Bucket, festes Fenster, gleitendes Fenster, 429 Antworten, Ratenbe…

Artikel lesen →
Testautomatisierung

Spott in Python: unittest.mock, Patch und die Fehler, die Tests zum Lügen machen

Mocking in Python mit unittest.mock, getestet: Mock und return_value, side_effect, Patchen, wo ein Name verwendet wird, Spezifikation und Autospec, …

Artikel lesen →
Softwaretests

Code-Abdeckung erklärt: Leitungs- und Zweigstellenabdeckung und was 100 % wirklich bedeutet

Erklärung der Codeabdeckung anhand eines echten Coverage.py-Laufs: Zeilen-, Zweig- und Bedingungsabdeckung, Lesen eines Berichts, warum bei 100 % Ab…

Artikel lesen →
Datenbanken & SQL

DELETE vs. TRUNCATE vs. DROP in SQL: Unterschiede, Rollback und Verwendungszweck

DELETE vs. TRUNCATE vs. DROP erklärt mit getestetem SQL: was jeweils entfernt wird, Rollback, Trigger, Identitätsrücksetzung, Geschwindigkeit und wi…

Artikel lesen →
Datenbanken & SQL

Erklärte SQL-Ansichten: Erstellen, nutzen und vermeiden Sie Fallstricke mit Beispielen

SQL-Ansichten anhand der von uns ausgeführten Abfragen erklärt: Erstellen einer Ansicht, Live-Ergebnisse, Ausblenden von Spalten, Leistung, aktualis…

Artikel lesen →
Softwareentwicklung

TypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler

TypeScript-Schnittstelle vs. Typ, überprüft mit dem echten Compiler: Was beide können, was nur einer kann, Deklarationszusammenführung, Erweiterunge…

Artikel lesen →
Softwareentwicklung

Python *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen

Python *args und **kwargs erklärt mit Code, den wir ausgeführt haben: Packen und Entpacken, Parameterreihenfolge, Nur-Schlüsselwort- und Nur-Positio…

Artikel lesen →
Softwareentwicklung

Python-Lambda-Funktionen: Syntax, tatsächliche Verwendung und wann man sie nicht verwendet

Python-Lambda-Funktionen erklärt mit Code, den wir ausgeführt haben: Syntax, Sortierung mit Schlüssel, Karte und Filter, Abschlüsse, die Late-Bindin…

Artikel lesen →
Künstliche Intelligenz

Was sind KI-Agenten? Wie sie funktionieren, mit einer einfachen Agentenschleife, die Sie ausführen können

Was sind KI-Agenten? Eine einfache Anleitung zur Agentenschleife, zu Tools, Speicher und Leitplanken, mit einer kleinen Python-Schleife, die wir aus…

Artikel lesen →
DevOps

Überwachung vs. Beobachtbarkeit: Der wahre Unterschied, mit Protokollen, Metriken und Traces

Überwachung vs. Beobachtbarkeit erklärt: bekannte und unbekannte Fehler, Protokolle, Metriken und Spuren, eine exemplarische Vorgehensweise für Chec…

Artikel lesen →
DevOps

Docker-Volumes vs. Bind Mounts: Containerdaten auf die richtige Art und Weise beibehalten

Docker-Volumes vs. Bind-Mounts erklärt: Warum Containerdaten verschwinden, benannte Volumes, Bind-Mounts, tmpfs, Compose-Beispiele, Backups, Berecht…

Artikel lesen →
Testautomatisierung

TDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte

TDD vs. BDD erklärt mit einer Rabattfunktion, die in beide Richtungen aufgebaut ist: Rot-Grün-Refaktor mit Code, den wir ausgeführt haben, Gegeben-W…

Artikel lesen →
Softwareentwicklung

Git merge vs rebase: Unterschiede, Beispiele und wann man was nutzt

Git merge vs rebase erklärt mit echter Log-Ausgabe, einer Vergleichstabelle, der goldenen Regel des Rebase und einem sicheren Team-Workflow.

Artikel lesen →
Softwareentwicklung

Python List Comprehension: Syntax, Beispiele und wann man darauf verzichtet

Python List Comprehension erklärt: Syntax, Filter, if-else, verschachtelte Schleifen, gemessene Zeiten und Fälle, in denen eine normale for-Schleife…

Artikel lesen →
Datenbanken & SQL

SQL Joins erklärt mit Beispielen (Inner, Left, Right, Full)

SQL Joins Schritt für Schritt mit Beispieltabellen und Abfragen verstehen: INNER, LEFT, RIGHT, FULL, CROSS und SELF, plus typische Fehler und Perfor…

Artikel lesen →