I programmatori di oggi utilizzano sempre più pratiche agili nel loro lavoro quotidiano. Anche i progetti che seguono un ciclo di vita di sviluppo del software standard possono trarre vantaggio dal loro adattamento. I test automatici e il TDD hanno portato più fiducia nel nostro lavoro, hanno facilitato l'implementazione di modifiche alle funzionalità esistenti e spesso ci hanno portato a una migliore progettazione del codice. Ma ora non basta più. Dobbiamo spingere i benefici dei test al limite e il BDD lo consente. Il BDD si basa sul TDD e aggiunge alle sue pratiche molto valore. Porta un linguaggio onnipresente nel progetto e consente una migliore comunicazione tra cliente e sviluppatori. Offre molto ai project manager e ai leader, ma rende anche la vita degli sviluppatori molto più semplice. Seguendo i principi del BDD si ottengono requisiti chiari, i test sono più facili da capire e possono fungere da documentazione. Il BDD sposta l'attenzione sugli argomenti di test e ci dà la certezza di testare ciò che dovremmo testare: il comportamento.
Se si utilizza il TDD, iniziare con il BDD sarà facile: si tratta fondamentalmente di un insieme di best practice. Il BDD ha un insieme di semplici regole che indicano come scrivere le specifiche e cosa testare. Le specifiche sono divise in tre parti: Given (impostazione delle condizioni di test), When (invocazione di azioni sull'oggetto) e Then (asserzioni). I test dovrebbero avere nomi descrittivi e i framework di test esistenti consentono di utilizzare metodi e asserzioni simili al linguaggio naturale; tutto ciò, combinato, ci permette di ottenere test leggibili sia da utenti tecnici che non tecnici. Buone convenzioni di denominazione si rivelano utili durante i test di regressione.
Il BDD viene fornito anche con una serie di linee guida per i soggetti dei test. A differenza del TDD, sposta l'attenzione dal collaudo dell'implementazione al collaudo del comportamento; l'uso di questo metodo porta a una progettazione migliore e offre maggiore flessibilità quando si devono introdurre cambiamenti. Le specifiche dovrebbero essere come requisiti scritti ed eseguibili del cliente - quelle di alto livello dovrebbero fungere da test di accettazione. L'obiettivo è scrivere i test in modo da doverli modificare solo quando cambiano i requisiti. L'uso del BDD ci dà la certezza di testare ciò che deve essere realmente trattato ed è un approccio più pragmatico del TDD.
Se volete vedere il BDD in azione, vi consigliamo Ruby. È un linguaggio potente e divertente da usare e dispone di un eccellente set di strumenti BDD.
Cetriolo
Cucumber è il framework più popolare per il BDD in Ruby. Introduce un linguaggio speciale, chiamato Gherkin, in cui scrivere i test. A differenza di RSpec, le caratteristiche descritte in Gherkin sono testo semplice, non codicee come tale può - e deve - essere compreso da chiunque, in particolare dal cliente.
La funzione di Cucumber si presenta così (esempio tratto dal wiki di Cucumber):
Caratteristica: Testo sintetico ma descrittivo di ciò che si desidera ottenere.
Descrizione testuale del valore di business di questa funzionalità
Regole di business che regolano l'ambito della funzionalità
Qualsiasi informazione aggiuntiva che renda più facile la comprensione della funzionalità.
Scenario: Una situazione aziendale determinabile
Data una precondizione
E qualche altra precondizione
Quando un'azione dell'attore
E qualche altra azione
E un'altra azione ancora
Allora si ottiene un risultato testabile
E succede anche qualcos'altro che possiamo verificare
Scenario: Una situazione diversa
...
Le caratteristiche saranno descritte in dettaglio più avanti.
Utilizzo di Cucumber in Ruby on Rails
Installazione
Il primo passo per utilizzare il cetriolo nella progetto lo sta installando. Aggiungete queste due gemme al vostro file Gem:
gruppo :test do
gemma 'cucumber-rails', :require => false
gemma 'database_cleaner'
fine
Impacchettateli eseguendo installare il bundlee generare gli script e le directory di Cucumber con il seguente comando:
rails generate cucumber:install
Questo creerà config/cucumber.yml, script/cucumber e caratteristiche/ directoryche conterrà .feature così come le definizioni dei passi e i file di supporto. Per eseguire le funzioni, utilizzare un nuovo comando rake:
rastrellare i cetrioli
Caratteristiche
Diamo un'occhiata più da vicino alle funzionalità. Una funzionalità è qualcosa che l'applicazione ha o fa, ad esempio l'invio periodico di newsletter o la possibilità di condividere pubblicamente le proprie foto. Una funzionalità è composta da più scenari, che descrivono il funzionamento di questa funzionalità in contesti diversi.
Per dimostrare l'uso di base di Cucumber in Rails, scriveremo una funzione da zero. Questa funzione di esempio sarà la prima che scriveremo nell'applicazione, che verrà mostrata nella seconda parte di questo articolo. Questa applicazione consentirà all'utente di creare articoli e negozi (i negozi vendono articoli) e di creare liste della spesa.
Nella versione più semplice, dopo aver compilato la Lista della spesa, l'applicazione mostrerà in quali negozi gli articoli desiderati dall'utente sono più economici.
Per prima cosa, creare un nuovo file chiamato crea_voce.caratteristica nel caratteristiche/ directory. All'inizio di una cartella .feature c'è un file Caratteristica parola chiave, seguita da una breve descrizione della stessa. Ad esempio:
Funzione: Creazione di elementi
Nelle righe successive si può scrivere un obiettivo di business che implementerà questa funzionalità. Poiché Cucumber ignora il testo scritto prima del primo scenario, non è necessario scrivere nulla, ma è sicuramente una buona idea.
Per creare facilmente liste della spesa con gli articoli venduti nei negozi vicini
Come utente
Voglio aggiungere articoli al sistema
Nello snippet, si può vedere un modello abbastanza popolare con cui si possono descrivere gli obiettivi aziendali. Si compone di tre parti: perché la funzionalità è necessaria, chi la vuole e di cosa si tratta. Naturalmente, non è necessario seguire questo schema, ma assicuratevi di includere le risposte a queste tre domande nella vostra descrizione.
Scenari
Quindi, scriviamo alcuni scenari. Ogni scenario inizia con la parola chiave "Scenario" e contiene più fasi.
Scenario: creazione di un articolo unico
Dato che esiste un articolo "Latte
Quando vado alla pagina principale
E creo l'articolo "Pane
Poi vedo "Pane" nell'elenco degli articoli
Quindi, se qualcuno ha creato un elemento chiamato Latte, la creazione di Pane è possibile e comporta la comparsa di Pane nell'elenco degli elementi. Non dovremmo testare la creazione di un record nel database, poiché questo fatto non ha alcun valore reale per il cliente.
I passi di Scenario utilizzano tre parole chiave principali:
Datoper fornire un contesto allo scenario
Quandoper descrivere le azioni
Allora, per la descrizione dei risultati
È importante notare che Cucumber ignora la parola chiave del passo con cui inizia e corrisponde solo alla parte successiva. Pertanto, è possibile iniziare i passi con "E" ovunque risulti naturale. L'unica regola per scegliere la parola chiave giusta è che lo scenario deve essere facilmente comprensibile.
Definizioni dei passi
L'esecuzione di Cucumber produce ora questo output:
[...]
Funzione: Creazione di articoli
Per creare facilmente liste della spesa con gli articoli venduti nei negozi vicini
Come utente
Voglio aggiungere articoli al sistema
Scenario: creazione di un articolo unico # features/create_item.feature:6
Dato che esiste un articolo "Latte" # features/create_item.feature:7
Passo non definito: "esiste un elemento "Latte"" (Cucumber::Undefined)
[...]
Questo perché Cucumber non sa cosa si intende quando si dice "c'è un elemento latte". Per aggiungere un significato ai propri passi, è necessario definirli in Definizioni_di_fase directory.
Un modo consigliato per organizzare le definizioni dei passi è dividerle in base al dominio. Ad esempio, la maggior parte dei passi che abbiamo creato appartiene al dominio Item. Pertanto, dovremmo creare un file chiamato step_definitions/item_steps.rb e inserire il seguente codice:
Dato "esiste un elemento "$name"", fare |nome|
Fabbrica :articolo, nome: nome
fine
Quando "creo un articolo "$name"" do |nome|
all'interno di "#new_item" fare
compilare "Nome", con: nome
Cliccare su "Crea".
fine
fine
Poi "Vedo "$name" nell'elenco degli elementi" do |nome|
all'interno di ".items" do
aspettarsi che(pagina).to abbia_contenuto nome
fine
fine
Le definizioni dei passi si basano solitamente su Capybara. Se non avete familiarità con Capybara, consultate i link alla fine di questo articolo.
C'è un'altra fase che deve essere definita e che non rientra tra le fasi di Item. Si potrebbe inserire in main_page_steps.rb:
Quando "vado alla pagina principale", fare
visita il percorso_radice
fine
Conclusione
Questa è una storia molto semplice per una funzione molto semplice. Il suo scopo era quello di dimostrare i concetti fondamentali del BDD, così come sono utilizzati in Cucumber. Scrivere buone storie richiede però qualcosa di più. Come sviluppatore, dovrete cambiare completamente la vostra mentalità: dimenticatevi dell'implementazione e concentratevi invece sugli obiettivi di business. Cucumber facilita questa transizione grazie all'uso intelligente delle storie in testo semplice.