BDD in .NET - Chicken or Egg o ..?

6

Predicato: sono nuovo di zecca per BDD / TDD, ma ho fatto i miei compiti.

Sto cercando di mettere in pratica tutto ciò che ho letto / imparato con VS2010, SpecFlow e NUnit. Le cose stanno funzionando, ma sta rapidamente diventando uno scenario di pollo / uovo all'interno di una sfocatura di unità e test di accettazione. Spero che la soluzione di queste domande BASIC renderà tutto click .

Dalla mia lettura, mi aspettavo di:

  1. Scrivi una feature
  2. Definisci i test di accettazione che falliscono
  3. Definisci test unitari che falliscono
  4. Verifica passaggi unità
  5. Ora il test di accettazione passa
  6. Scrivi la prossima caratteristica

Tutto ha perfettamente senso, sto solo facendo fatica a vedere cosa c'è nel codice ...

In pratica:

  1. Scrivi una feature con scenari - bene.
  2. Generazione delle definizioni passo - bene.
  3. Ahhh.

Il completamento delle definizioni dei passaggi (fornire il contesto in GIVEN, impostare le cose in WHEN e fare assertion in THEN) costituisce un test di accettazione completato? Scrive qui classi e metodi prima come se li avessi già definiti e generi codice skeleton tramite l'IDE? Presumibilmente, l'asserzione richiede un qualche tipo di implementazione per funzionare, ma il codice di implementazione non sarà stato testato unitamente? Ahhh.

Ho esaminato un certo numero di progetti di esempio e basi di codice, ma poiché sono tutti completi, c'è poco senso di ordinare in termini di processo di sviluppo.

Qualsiasi chiarimento su passaggi, esempi, ecc. sarebbe fantastico!

    
posta Tom Tom 10.08.2012 - 18:02
fonte

3 risposte

10

Il tuo ordine è sbagliato, methinks:

  1. Definisci i test di accettazione che falliscono
  2. Definisci test unitari che falliscono
  3. Fai passare i test delle unità scrivendo la logica richiesta per la funzione
  4. Fai passare il test di accettazione integrando la logica nel sistema esistente
  5. Ripeti con il prossimo requisito definito

Fondamentalmente, sia in TDD che in BDD, definisci sempre cosa dovrebbe fare il tuo nuovo codice prima di scrivere una riga di quel codice. Quindi, analizzandolo, il vero processo è:

  1. Leggi i requisiti per il prossimo articolo e suddividilo in singoli pezzi che possono essere definiti in SpecFlow come asserzioni usando le clausole "Given", "When" e "Then".
  2. Scrivi la prima asserzione in SpecFlow. Questo è il tuo "test di accettazione" e fallirà perché il comportamento non è nel sistema.
  3. "Drill down": identifica l'oggetto codice a cui è più direttamente interagito, al di fuori dei limiti del sistema, che deve mostrare il comportamento appena definito. Quell'oggetto non esiste necessariamente nella base di codice corrente. Scrivi un test che asserisce che l'oggetto mostra il comportamento desiderato. Ripetere; trova l'oggetto (o gli oggetti) che quello che hai appena testato deve interagire per mostrare il comportamento definito. Definisci i test che asseriscono che questi oggetti fanno ciò di cui hanno bisogno. Ripeti fino a quando non identificherai una o più righe di codice reale all'interno di un metodo che non esiste ancora o che deve cambiare per iniziare a mostrare il comportamento. Lungo il percorso, i test che devono toccare un altro oggetto, la rete, il file system, il DB, ecc. Per avere valore sono "test di integrazione"; i test che possono operare entro i limiti di una singola classe, o che hanno un valore dato "dati di test" sotto forma di oggetti derisi, sono "unit test".
  4. Ora inizia la codifica della funzione effettiva. Fai quello che devi fare per superare i test che hai scritto e tutti gli altri test del sistema; prima unità, poi integrazione, quindi accettazione. Non è inaudito scrivere un codice che passi per primo; che indica o una cosa negativa (non hai fatto le asserzioni corrette, torna al punto 3) o buona (il comportamento che hai bisogno esiste già, vai avanti). Inoltre, non è inaudito apportare modifiche che superano un nuovo test ma non superano quelle precedenti; o hai apportato una modifica errata o le asserzioni del vecchio test ora non sono corrette alla luce del nuovo requisito. È tuo compito determinare quale.
  5. Una volta che tutto è "verde", rifatta il codice che hai scritto per superare i test; organizzalo, unisci blocchi di codice che fanno la stessa cosa, aderisci a buoni schemi di codifica. Assicurati che tutti i test passino, naturalmente.
  6. Ripeti dal passaggio 2 con la prossima asserzione dei requisiti del racconto.
  7. Ripeti con la storia successiva.

Lungo la strada, è perfettamente normale dover definire un nuovo oggetto o membro di oggetto che non è mai esistito prima, ma che ora deve esistere e funzionare correttamente. Ecco dove TDD inizia a rimborsarti, e dove l'assistenza per il refactoring come ReSharper si ripaga da sola più volte; semplicemente codifica il test come se l'oggetto codice fosse già esistente . Questo codice ovviamente non verrà compilato; questo è il tuo primo obiettivo e ReSharper può risolvere praticamente tutto il rosso che vedrai con alcune pressioni di Alt + Invio. Una volta compilato, il test fallisce ancora perché esiste lo scheletro, ma la logica continua a non funzionare. Codifica questa logica fino a quando il test non passa, e poi passa a .

    
risposta data 10.08.2012 - 18:32
fonte
2

Generalmente, quando fai il BDD ti immergi e ti allontani da una posizione TDD. Il test di accettazione definisce l'ambito della funzionalità. All'interno della definizione del passo, dovresti "guidare" i tuoi scenari. Questo è più vicino a quello che fa l'utente, quindi forse usi un driver della GUI come il Selenium. A questo livello stai pensando in termini di ruolo della tua storia (come ...) e le azioni disponibili nel contesto del passo definito. Forse questa è una API molto di alto livello, forse è il flusso interfunzionale di un processo. L'attributo principale è che questo è al livello di valore per il ruolo e dovrebbe apparire come un utente / consumatore che agisce.

Quando definisci la superficie di alto livello della tua implementazione, ti immergi nella modalità TDD. Esegui un'iterazione TDD, quindi torna alla modalità BDD.

Immagina uno scenario per un sito web:

  1. Dato un visitatore
  2. E il visitatore si trova nella vista di registrazione
  3. E il visitatore ha fornito tutti gli input richiesti
  4. Quando il visitatore registra
  5. Quindi viene creato un utente registrato
  6. E l'utente registrato corrisponde all'ingresso del visitatore
  7. E un'e-mail di conferma viene inviata all'indirizzo di posta elettronica fornito dal visitatore

Quindi, le definizioni dei passaggi devono essere tutte compilate in qualche modo. Questa è la modalità di implementazione di BDD.

Dato un visitatore? Ok, cosa significa visitare il sito? Richiesta HTTP? Come lo so? I cookie?

Nella vista di registrazione? Dovrei usare Watin per guidare questo processo. Ci sono degli endpoint URI? Come guido la mia applicazione?

Input richiesti? Come posso fornire a livello di codice il mio sistema con l'input dell'utente? Modulo HTML?

Registri visitatori? Come viene attivata questa azione? È un post HTTP? A questo punto, visualizzi la vista di livello superiore del tipo di script del tuo sistema.

In ogni punto, potresti ritagliare il tuo progetto usando TDD.

Dato un visitatore? Ok, nuove scelte di design. Un visitatore è un tipo nel mio sistema? O li chiamo Utente con registrato = falso? Usa TDD per guidare il design di un visitatore. Pensa a gestire l'autenticazione in questo livello.

Registri visitatori? È un servizio? Voglio dire qualcosa come Register (visitatore) nel mio test e guidarlo usando TDD.

L'email è stata inviata? Ancora una volta, c'è un design di alto livello e di alto livello da dare una svolta.

In breve, gli scenari BDD (raccolte di definizioni di passaggi) sono affermazioni sui mondi. Condizioni preliminari, azione, postcondizioni (come Arrange, Act, Assert) che sono importanti per l'utente del sistema. TDD è importante per il programmatore / progettista del sistema. Ma tu usi entrambi quando pratichi BDD.

    
risposta data 10.08.2012 - 18:45
fonte
1
  1. Parla attraverso gli scenari in conversazione con il tuo esperto o proxy aziendale.
  2. Interroga gli scenari. Trova altri scenari.
  3. Scrivi gli scenari in basso. Onestamente, non deve essere in SpecFlow per iniziare.
  4. Se si tratta di una nuova interfaccia utente, probabilmente la prima volta si sbaglia, quindi se inizi a scrivere scenari automatici qui potresti trovarti a picchiarli orribilmente con loro. Non scrivere scenari automatizzati per nuove interfacce utente. Aspetta che si stabilizzi. Ottieni qualcosa di piccolo funzionante - può avere dati hardcoded se lo desideri. Il test delle unità va bene qui. Ricordati di ottenere un feedback dal tuo esperto di business.
  5. Ora che l'interfaccia utente si è stabilizzata, puoi automatizzare gli scenari.
  6. Ora l'interfaccia utente si è stabilizzata, aggiungi un altro scenario che cattura il prossimo comportamento e fallo funzionare.

Questo è più o meno come va il mio ciclo. È perfettamente OK non scrivere test automatici per una nuova interfaccia utente e scriverli successivamente.

Assicurati che o la tua attività abbia chiaramente articolato ciò che vogliono, o sei consapevole che sono incerti e hai elaborato un meccanismo per dare loro qualcosa da provare in modo che possano fornire un feedback. In quella seconda situazione potresti non essere in grado di venire in ogni caso con scenari particolarmente coerenti.

    
risposta data 10.08.2012 - 18:43
fonte

Leggi altre domande sui tag