Quali sono le scuole di TDD a Londra e Chicago?


88

Ho sentito parlare dello stile londinese contro lo stile di Chicago (a volte chiamato stile di Detroit) di Test Driven Development (TDD).

Workshop del gruppo di utenti della programmazione Utah Extreme:

Il TDD in stile interazione è anche chiamato mockist o stile londinese dopo il club Extreme Tuesday di Londra, dove divenne popolare. Di solito è in contrasto con TDD in stile Detroit o classico che è più basato sullo stato.

L'officina di Jason Gorman :

Il seminario copre sia la scuola di TDD di Chicago (test di comportamento statale e triangolazione), sia la scuola di Londra , che si concentra maggiormente su test di interazione, derisione e TDD end-to-end, con particolare enfasi su Responsibility-Driven Design e il Di ', non chiedere l' approccio a OO recentemente ri-divulgato dall'eccellente libro di Software guidato da test in crescita di Steve Freeman e Nat Pryce .

Il post classico TDD o "London School"? di Jason Gorman è stato utile, ma i suoi esempi mi hanno confuso, perché usa due esempi diversi invece di un esempio con entrambi gli approcci. Quali sono le differenze? Quando usi ogni stile?

Risposte:


76

Supponiamo di avere una classe chiamata "libro mastro" un metodo chiamato "calcola" che utilizza un "Calcolatore" per eseguire diversi tipi di calcoli a seconda degli argomenti passati a "calcola", ad esempio "moltiplica (x, y)" o "sottrai ( x, y) ".

Ora supponiamo che tu voglia testare cosa succede quando chiami ledger.calculate ("5 * 7").

La scuola London / Interaction vorrebbe farti affermare se è stato chiamato Calculator.multiply (5,7). I vari framework di derisione sono utili per questo, e può essere molto utile se, ad esempio, non si possiede la proprietà dell'oggetto "Calcolatrice" (supponiamo che sia un componente esterno o un servizio che non è possibile testare direttamente, ma lo si fa sapere che devi chiamare in un modo particolare).

La scuola di Chicago / State vorrebbe farti affermare se il risultato è 35. I framework jUnit / nUnit sono generalmente orientati a farlo.

Entrambi sono test validi e importanti.


Esempio molto bello.
sevenseacat,

1
Aggiungerò alcuni motivi in ​​più per l'utilizzo di ciascuno di essi: se l'importante è determinare se qualcosa è cambiato o non è cambiato in base all'azione intrapresa (ad esempio, il ledger.bucket.value diventa 35 quando ledger.calculate ("5 * 7 ") viene chiamato), si desidera utilizzare asserzioni di stato (scuola di Chicago). Ciò è molto utile quando si ha il pieno controllo dello stato del sistema prima che venga chiamato il metodo e quando si controlla effettivamente ciò che fa il metodo.
Matthew Flynn,

1
Se la cosa importante è sapere che viene chiamato un secondo metodo (ad esempio, Calculator.multiply (5, 7)), si desidera utilizzare le asserzioni di attività, come attraverso un oggetto simulato. Ciò è molto utile se il metodo chiamato ha l'effetto collaterale desiderato (ad es., Salvataggio dei dati, incremento di un contatore, invio di un messaggio, ecc.) Se non si controlla realmente ciò che fa il metodo, quindi il valore restituito potrebbe essere incoerente . Inoltre, se non riesci a controllare facilmente lo stato del sistema, la cosa migliore che puoi fare è determinare quali attività si verificano.
Matthew Flynn,

L'approccio di Londra è utile quando la classe Calcolatrice è potenzialmente lunga per qualche motivo, o coinvolge una rete e quindi potrebbe essere flakey nelle configurazioni dev / qa. Vale a dire il deridere consente ai test di essere veloci e affidabili nei casi in cui altrimenti non sarebbe possibile.
Kevin,

1
L'approccio di Londra sostiene anche di fornire segnali di feedback più chiari, perché se Calculatorregredisce multiply, vedrai fallire due test: il test del libro mastro e il test della calcolatrice, ma solo un test fallisce se prendi in giro la calcolatrice. Ciò potrebbe rendere più semplice individuare l'origine del bug, soprattutto se il sistema è complesso.
Matthias,

30

L'articolo Mocks Aren't Stubs , di Martin Fowler, è una buona introduzione all'argomento.

A seconda dello stile di progettazione che scegli (e dei principi di progettazione su cui costruisci i tuoi programmi), ci sono almeno due modi di vedere un oggetto:

  1. Come unità che esegue calcoli basati su input. Come risultato di questo calcolo, l'oggetto può restituire un valore o modificarne lo stato.
  2. Come elemento attivo che comunica con altri elementi nel sistema passando messaggi.

Nel primo caso, sei interessato a ciò che viene fuori dall'elaborazione o in quale stato viene lasciato l'oggetto dopo tale elaborazione. Qui è dove metodi come assertEquals()inserire l'immagine. In questo caso, non importa molto quali altri oggetti fossero coinvolti nell'elaborazione, quali metodi sono stati chiamati, ecc. Questo tipo di verifica è chiamata verifica basata sullo stato ed è lo stile "classico".

Nel secondo caso, poiché la maggior parte degli oggetti non restituisce nemmeno alcun risultato (ad esempio voidmetodi in Java), si è più interessati a come gli oggetti comunicano tra loro e se passano i messaggi giusti nelle circostanze imposte dal test. Queste interazioni sono generalmente verificate con l'ausilio di schemi simulati. Questo tipo di verifica si chiama verifica basata sul comportamento o basata sull'interazione. Una delle sue implicazioni è la tecnica chiamata Behavior Driven Development, con la quale si sviluppa una classe assumendo che i suoi collaboratori esistano già (anche se potrebbero non esistere ancora), in modo da poter codificare rispetto alle loro interfacce.

Nota che questa non è una scelta / o. Puoi avere uno stile di design che mescoli entrambi gli approcci per ottenere il meglio da ciascuno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.