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.
- 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:
- Das Team einigt sich auf das Verhalten und schreibt ein BDD-Szenario. Es schlägt fehl, weil noch nichts existiert.
- Ein Entwickler verwendet TDD, um die benötigten kleinen Einheiten zu erstellen.
- Unit-Tests werden bestanden, und schließlich auch das Szenario.
- 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
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.
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.
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 →DevOpsErklä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 →SoftwareentwicklungAPI-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 →TestautomatisierungSpott 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 →SoftwaretestsCode-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 & SQLDELETE 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 & SQLErklä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 →SoftwareentwicklungTypeScript-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 →SoftwareentwicklungPython *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 →SoftwareentwicklungPython-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 IntelligenzWas 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 →DevOpsDocker-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 →TestautomatisierungTDD 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 →SoftwareentwicklungGit 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 →SoftwareentwicklungPython 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 & SQLSQL 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 →