TDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno

  1. Home
  2. Blog
  3. Testare l’automazione

Automazione dei test

TDD vs BDD: Differenze chiave, una funzionalità realizzata in entrambi i modi e quando utilizzarli ciascuno

TDD aiuta gli sviluppatori a progettare il codice corretto. BDD aiuta un intero team a concordare cosa dovrebbe fare il software. Scopri la stessa funzionalità di sconto creata con ciascun approccio e scopri come i due interagiscono.

9 min di lettura
TDD vs BDD: differenze chiave, una funzionalità costruita in entrambi i modi e quando utilizzarli ciascuno

Punti chiave

  • TDD significa scrivere prima un test fallito, poi il codice sufficiente per superarlo, quindi riordinare.
  • BDD descrive il comportamento in un linguaggio condiviso, solitamente come Dato, Quando, Allora.
  • TDD guida principalmente la progettazione del codice. BDD costruisce principalmente una comprensione condivisa.
  • Non sono rivali e molti team utilizzano BDD per le funzionalità e TDD per i dettagli riportati di seguito.

Il dibattito TDD vs BDD viene spesso inquadrato come la scelta di una parte. In realtà, rispondono a domande diverse. Lo sviluppo basato sui test chiede se il codice fa ciò che lo sviluppatore intendeva, mentre lo sviluppo basato sul comportamento chiede se il team è d’accordo su cosa dovrebbe fare il software.

Per rendere concreta la differenza, creiamo una piccola funzione di sconto con ogni approccio. Abbiamo eseguito il codice su Python 3.13, utilizzando la libreria standard, e i risultati seguenti provengono da quell’esecuzione. La parte BDD utilizza un nostro piccolo runner per mostrare il meccanismo, quindi un progetto reale utilizzerebbe uno strumento come Cucumber o si comporterebbe invece.

La risposta breve

Lo sviluppo basato sui test (TDD) è una pratica di codifica. Scrivi un piccolo test fallito, fallo passare con il codice più semplice e poi migliori il design. I test sono scritti in codice e principalmente dagli sviluppatori. Kent Beck ha reso popolare la pratica.

Lo sviluppo guidato dal comportamento (BDD) è una pratica di collaborazione nata dal TDD e Dan North ha introdotto il termine. Sviluppatori, tester e uomini d’affari concordano su esempi di come dovrebbe comportarsi il sistema, scritti in un linguaggio semplice, e tali esempi possono quindi essere automatizzati.

TDD e BDD fianco a fianco

Aspetto TDD BDD
Obiettivo principale Codice corretto e ben progettato Comprensione condivisa del comportamento
Scritto dentro Linguaggio di programmazione Linguaggio semplice, come Gherkin
Scritto da Sviluppatori Business, QA e sviluppatori insieme
Leggibile da Sviluppatori Tutti nella squadra
Livello tipico Unità Caratteristica o accettazione
Punto di partenza Un test fallito Una conversazione con esempi
Ciclo Rosso, verde, refactoring Scopri, formula, automatizza
Strumenti comuni pytest, JUnit, Jest Cetriolo, comportati bene, SpecFlow, Reqnroll

La caratteristica

Ecco la regola aziendale che implementeremo: Gli ordini di 1.000 o più ricevono uno sconto del 10%. I membri ricevono uno sconto extra del 5% su questi ordini.

Può sembrare chiaro, ma è già ambiguo. Un membro che spende 500 ottiene uno sconto del 5%? La frase dice “quegli ordini”, quindi presumiamo di no. Tienilo a mente, perché questo è esattamente il tipo di domanda che BDD è progettato per far emergere presto.

Costruirlo con TDD

TDD segue un breve ciclo noto come red, green, refactor:

Passo Cosa fai
Rosso Scrivi un test per un comportamento che ancora non esiste e guardalo fallire
Verde Scrivi il codice più semplice che lo faccia passare
Refactoring Migliora il codice, mantenendo i test verdi

Questi sono i nostri test, con uno per ogni regola:

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)

Abbiamo quindi scritto il codice in tre fasi, eseguendo i test dopo ciascuna. Una sessione TDD rigorosa aggiunge un test alla volta e mostra la stessa progressione:

Fase 1: la cosa più semplice

def discount(total, is_member):
    return 0

# 3 tests, 2 failed
#   test_member_gets_extra_five_percent
#   test_ten_percent_from_1000

Restituire zero sembra sciocco, ma dimostra che i test possono effettivamente fallire e l’unico test che supera è la regola “nessuno sconto”.

Fase 2: aggiungere la soglia

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: aggiungi membri e ripulisci

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

Passano tutti e tre. Ma leggi attentamente questa versione. Offre a un membro che spende 500 uno sconto del 5%, che non è ciò che pensavamo significasse la regola. Nessun test ha coperto quel caso, quindi niente lo ha segnalato. TDD protegge solo il comportamento che pensavi di testare. Questa è una vera limitazione, ed è il motivo per cui le conversazioni sugli esempi sono così importanti.

Perché il ciclo è importante

  • Il rosso dimostra che il test funziona. Un test che non ha mai fallito potrebbe non testare nulla.
  • Il verde ti mantiene concentrato. Scrivi solo il codice necessario, il che aiuta a prevenire un’ingegneria eccessiva.
  • Refactor mantiene elevata la qualità. I test ti danno la sicurezza necessaria per modificare il progetto in modo sicuro.
  • Influenza il design. Il codice difficile da testare è spesso troppo strettamente accoppiato e lo noti subito.

Il nostro tutorial pytest mostra un modo più conveniente per scrivere test come questi e l’analisi dei valori limite spiega perché abbiamo scelto 999 e 1000 come valori.

Costruirlo con BDD

BDD inizia con una conversazione, non con gli strumenti. Spesso si tratta di un breve incontro noto come i tre amigos, con un addetto al prodotto, uno sviluppatore e un tester che discutono esempi concreti:

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.

Quell’unico scambio avrebbe rilevato il problema nel nostro codice TDD. Quindi registrano i loro esempi in un formato strutturato chiamato 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
Parola chiave Scopo
Dato La situazione di partenza
Quando L’azione o l’evento
Poi Il risultato atteso

Chiunque nel team può leggerlo e dire “sì, è giusto” o “no, è sbagliato”. Anche se non lo automatizzi mai, lo scenario ha già svolto un lavoro utile.

Collegamento dei passaggi al codice

Gli strumenti collegano ciascuna riga in linguaggio semplice a una funzione, chiamata definizione del passaggio. Per mostrare l’idea, abbiamo scritto noi stessi una piccola versione ed eseguito il primo scenario:

@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

Gli strumenti reali aggiungono parametri, in modo che un singolo passaggio possa corrispondere sia a “1000” che a “500”, oltre al reporting. Il risultato è una documentazione vivente: una semplice descrizione del sistema che fallisce clamorosamente se smette di essere vera.

Suggerimento: Il valore di BDD risiede nella conversazione. I team in cui una persona scrive Gherkin da sola una volta terminato il codice ottengono il costo dello strumento, senza quasi alcun vantaggio.

Scrivere buoni scenari

Debole Meglio
Quando faccio clic sul pulsante con ID "btn-77" Quando applico il coupon
Allora il risultato è corretto Quindi l'importo da pagare è 850
Venti passi in uno scenario Un comportamento per scenario
Descrive lo schermo Descrive l’intento commerciale

Gli scenari che descrivono clic e ID campo si interrompono a ogni riprogettazione e i lettori aziendali smettono di leggerli. Conserva i dettagli dell’interfaccia utente nel codice del passaggio. Questi scenari sono cugini stretti degli esempi in caso di test vs scenario di test e sono spesso utilizzati anche nei test di accettazione dell’utente.

Usandoli entrambi insieme

I due si inseriscono naturalmente in un flusso di lavoro “outside-in”:

  1. Il team concorda sul comportamento e scrive uno scenario BDD. Fallisce, perché non esiste ancora nulla.
  2. Uno sviluppatore utilizza TDD per costruire le piccole unità necessarie.
  3. I test unitari vengono superati e, alla fine, anche lo scenario.
  4. Tutto viene eseguito nella tua pipeline CI/CD.

Mantieni ciascuno al giusto livello. Dovresti avere alcuni scenari per comportamenti importanti e molti test unitari veloci per i dettagli. La nostra guida ai test unitari e di integrazione copre l’equilibrio.

Strumenti

Lingua TDD (test unitario) BDD
Pitone pytest, unittest comportati bene, pytest-bdd
JavaScript Scherzo, Vitest Cucumber.js
Giava JUnit, TestNG Cetriolo-JVM
.NET xUnità, NUnità Reqnroll, SpecFlow

Quando utilizzarli ciascuno

Il TDD si adatta bene quando:

  • Stai scrivendo una logica complessa, come prezzi, analisi o autorizzazioni.
  • Stai correggendo un bug, poiché puoi riprodurlo prima con un test fallito.
  • Stai lavorando su un codice che cambierà spesso.

BDD si adatta bene quando:

  • Le regole aziendali sono complesse e le incomprensioni sono costose.
  • Le persone non tecniche leggeranno e discuteranno davvero gli scenari.
  • Diversi team necessitano di una definizione condivisa di come si comporta qualcosa.

Potrebbero essere eccessivi quando: stai scrivendo un prototipo usa e getta o esplorando un’idea tecnica poco chiara. Molti sviluppatori prima effettuano il picco, poi riscrivono con i test. Anche gli strumenti BDD sono uno scarso investimento se nessuno al di fuori dell’ingegneria esamina mai gli scenari. In tal caso, i test semplici con nomi validi sono più semplici.

Errori comuni

  • Trattare BDD come strumento di test. Il cetriolo senza collaborazione è solo un modo dettagliato per scrivere test.
  • Implementazione del test in TDD. I test legati ai dettagli privati ​​si interrompono durante ogni refactoring.
  • Saltando il passaggio del refactoring. Puoi superare i test anche se il codice è disordinato.
  • Scrivere test dopo il codice e chiamarlo TDD. È comunque utile, ma si perde il feedback sulla progettazione.
  • Scrivere troppi scenari dell’interfaccia utente. Questi diventano lenti e instabili. Vedi test instabili.
  • Alla ricerca di numeri di copertura. Una buona copertura non tiene ancora conto di comportamenti che nessuno ha preso in considerazione, come mostra il nostro esempio.

Considerazioni finali

TDD ti aiuta a costruire la cosa giusta e BDD ti aiuta a costruire la cosa giusta. Il nostro esempio di sconto ha mostrato entrambi i lati: il codice ha superato tutti i test, ma una semplice conversazione ha rivelato un presupposto sbagliato. Provalo sul tuo prossimo piccolo servizio. Scrivi tre esempi concreti con un collega prima di qualsiasi codice, quindi costruiscilo un test fallito alla volta.

Domande frequenti

Qual è la differenza principale tra TDD e BDD?

TDD si concentra sugli sviluppatori che scrivono test di codice falliti prima dell’implementazione. BDD si concentra su un intero team che concorda sul comportamento utilizzando esempi in linguaggio semplice.

Puoi usare TDD e BDD insieme?

Sì, e molte squadre lo fanno. Gli scenari BDD definiscono le funzionalità dall’esterno e TDD guida le unità più piccole di codice sottostanti.

BDD è migliore di TDD?

Nessuno dei due è complessivamente migliore, poiché risolvono problemi diversi. BDD aiuta con la comprensione condivisa e TDD aiuta con la progettazione del codice e un feedback rapido.

Cos’è il Gherkin?

Gherkin è un formato strutturato in linguaggio semplice per scrivere scenari, utilizzando parole chiave come Dato, Quando e Allora. Strumenti come Cucumber possono eseguirlo.

Il TDD rallenta lo sviluppo?

All’inizio può sembrare più lento, soprattutto durante l’apprendimento. I team spesso recuperano tempo riducendo i bug e apportando modifiche più sicure, anche se l’effetto varia in base al progetto.

Continua a imparare

Lavora con Stack Quora

Hai bisogno di aiuto con test, WordPress o SEO?

Aiutiamo i team a fornire software migliore e a far crescere i loro siti. Raccontaci a cosa stai lavorando e ti suggeriremo chiaramente il prossimo passo.

Continua a leggere

Altre guide su test, intelligenza artificiale e sviluppo moderno

Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.

Intelligenza artificiale

Spiegazione delle allucinazioni dell'intelligenza artificiale: perché i modelli linguistici inventano le cose e come ridurle

Spiegazione delle allucinazioni dell'intelligenza artificiale: cosa sono, perché i modelli linguistici le producono, tipi comuni, come ridurle con b…

Leggi l'articolo →
DevOps

Spiegazione delle variabili d'ambiente: file .env, segreti e configurazione eseguiti correttamente

Variabili d'ambiente spiegate con esempi Python che abbiamo eseguito: lettura e impostazione, perché ogni valore è una stringa, file .env, ereditari…

Leggi l'articolo →
Sviluppo software

Spiegazione della limitazione della velocità API: algoritmi, intestazioni e gestione degli errori 429

La limitazione della velocità dell'API spiegata con una simulazione che abbiamo eseguito: bucket di token, finestra fissa, finestra scorrevole, risp…

Leggi l'articolo →
Automazione dei test

Derisione in Python: unittest.mock, patch e gli errori che fanno mentire i test

Mocking in Python con unittest.mock, testato: Mock e return_value, side_effect, patch dove viene utilizzato un nome, specifiche e autospec, date moc…

Leggi l'articolo →
Test del software

Spiegazione della copertura del codice: copertura di linea o di filiale e cosa significa realmente il 100%.

Copertura del codice spiegata con una vera esecuzione di cover.py: copertura di linea, ramo e condizione, lettura di un rapporto, perché la copertur…

Leggi l'articolo →
Database e SQL

DELETE vs TRUNCATE vs DROP in SQL: differenze, rollback e quando utilizzarli

DELETE vs TRUNCATE vs DROP spiegato con SQL testato: cosa rimuove, rollback, trigger, reimpostazione dell'identità, velocità e come differiscono Pos…

Leggi l'articolo →
Database e SQL

Spiegazione delle visualizzazioni SQL: crea, utilizza ed evita le insidie, con esempi

Viste SQL spiegate con le query che abbiamo eseguito: creazione di una vista, risultati in tempo reale, nascondere colonne, prestazioni, viste aggio…

Leggi l'articolo →
Sviluppo software

Interfaccia TypeScript e tipo: differenze reali, testate con il compilatore

Interfaccia TypeScript vs tipo, verificata con il vero compilatore: cosa possono fare entrambi, cosa può fare solo uno, fusione delle dichiarazioni,…

Leggi l'articolo →
Sviluppo software

Spiegazione di Python *args e **kwargs: funzioni flessibili con esempi chiari

Python *args e **kwargs spiegati con il codice che abbiamo eseguito: compressione e decompressione, ordine dei parametri, argomenti solo per parole …

Leggi l'articolo →
Sviluppo software

Funzioni Lambda Python: sintassi, usi reali e quando non usarli

Funzioni lambda Python spiegate con il codice che abbiamo eseguito: sintassi, ordinamento con chiave, mappa e filtro, chiusure, trap dell'associazio…

Leggi l'articolo →
Intelligenza artificiale

Cosa sono gli agenti AI? Come funzionano, con un semplice ciclo di agenti che puoi eseguire

Cosa sono gli agenti IA? Una semplice guida al ciclo dell'agente, agli strumenti, alla memoria e ai guardrail, con un piccolo ciclo Python che abbia…

Leggi l'articolo →
DevOps

Monitoraggio vs osservabilità: la vera differenza, con log, metriche e tracce

Spiegazione del monitoraggio e dell'osservabilità: errori noti e sconosciuti, log, metriche e tracce, una procedura dettagliata sugli incidenti di p…

Leggi l'articolo →
DevOps

Volumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto

Volumi Docker e montaggi di collegamento spiegati: perché i dati del contenitore scompaiono, volumi denominati, montaggi di collegamento, tmpfs, ese…

Leggi l'articolo →
Automazione dei test

TDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno

TDD vs BDD spiegato con una funzione di sconto costruita in entrambi i modi: refactoring rosso-verde con il codice che abbiamo eseguito, scenari "Da…

Leggi l'articolo →
Sviluppo software

Git merge vs rebase: differenze, esempi e quando usare ciascuno

Git merge vs rebase spiegato con output reale del log, una tabella di confronto, la regola d'oro del rebase e un flusso di lavoro sicuro per i team.

Leggi l'articolo →
Sviluppo software

List comprehension in Python: sintassi, esempi e quando evitarla

List comprehension in Python spiegata: sintassi, filtri, if-else, cicli annidati, tempi misurati e i casi in cui un normale ciclo for è meglio.

Leggi l'articolo →
Database e SQL

SQL JOIN spiegati con esempi (Inner, Left, Right, Full)

Capisci i JOIN SQL passo dopo passo con tabelle e query di esempio: INNER, LEFT, RIGHT, FULL, CROSS e SELF, con errori comuni e consigli sulle prest…

Leggi l'articolo →