Test BDD con Behave¶
Estimated time to read: 5 minutes
Uno stile molto diverso di scrivere test è lo sviluppo guidato dal comportamento (behavior-driven development, BDD). Anziché limitarsi al codice Python, utilizza un linguaggio naturale formalizzato, Gherkin, per descrivere il comportamento desiderato, per poi implementare i test in Python.
Questo incoraggia la collaborazione tra stakeholder non tecnici, ingegneri non programmatori e sviluppatori nel processo di sviluppo. I partecipanti possono definire in anticipo il comportamento previsto per il software risultante in un linguaggio a loro comprensibile e possono quindi comunicare efficacemente i loro desideri e la loro comprensione ad altri partecipanti, come amministratori di database, ingegneri di rete, specialisti della sicurezza, designer UX e programmatori che implementano le funzionalità backend e frontend.
Esempio di linguaggio Gherkin¶
Quando si usa Gherkin, i documenti che si scrivono hanno lo scopo di descrivere una feature. I documenti sono file di testo semplice con estensione .feature
. Quindi, creiamo un tale file, per esempio example.feature
, e aggiungiamo il seguente contenuto:
Feature: Protection of user profile data
Scenario: User profile access requires login
Given I am not logged in
When I try to display the user profile
Then the website asks me to log in
La riga o il blocco "Feature" è soprattutto documentazione. Di solito si tratta di un titolo conciso ma descrittivo, a volte supportato da una descrizione più lunga sotto forma di user story (ad esempio, "Come <persona> voglio fare <qualcosa> in modo da <poterne trarre un beneficio>").
Dopodiché, il documento conterrà diversi blocchi "Scenario", tutti secondo lo schema "Dato <preparare> Quando <agire> Poi <verificare>".
Note
L'inglese è la lingua predefinita per il parsing dei file Gherkin. Tuttavia, se aiuta il team a comunicare meglio, si può usare anche la propria lingua madre. Behave offre le opzioni --lang-list
, --lang-help
e --lang
per questo scopo, ad es.
$ behave --lang-help it
Translations for Italian / italiano
And: * , E
Background: Contesto
But: * , Ma
Examples: Esempi
Feature: Funzionalità, Esigenza di Business, Abilità
Given: * , Dato , Data , Dati , Date
Rule: Regola
Scenario: Esempio, Scenario
Scenario Outline: Schema dello scenario
Then: * , Allora
When: * , Quando
Implementazione dei test BDD¶
Uno dei più popolari strumenti di test BDD per Python è Behave. Esiste anche un plugin per Pytest, pytest-bdd, che implementa un sottoinsieme del linguaggio Gherkin. Per il nostro viaggio attuale ci atteniamo a behave
. Possiamo installarlo usando Pip e poi eseguirlo dal terminale, ad es.
Per impostazione predefinita, behave
richiede che i feature files si trovino in una cartella chiamata features/
, che deve contenere anche una cartella steps/
come sede per i moduli Python che in seguito implementeranno i passi dello scenario. Creiamo questa struttura di cartelle e spostiamo il nostro feature file nel posto giusto, ad esempio
Ora possiamo eseguire behave
:
$ behave
Feature: Protection of user profile data # features/example.feature:1
Scenario: User profile access requires login # features/example.feature:3
Given I am not logged in # None
When I try to display the user profile # None
Then the website asks me to log in # None
Failing scenarios:
features/example.feature:3 User profile access requires login
0 features passed, 1 failed, 0 skipped
0 scenarios passed, 1 failed, 0 skipped
0 steps passed, 0 failed, 0 skipped, 3 undefined
Took 0m0.000s
You can implement step definitions for undefined steps with these snippets:
@given(u'I am not logged in')
def step_impl(context):
raise NotImplementedError(u'STEP: Given I am not logged in')
@when(u'I try to display the user profile')
def step_impl(context):
raise NotImplementedError(u'STEP: When I try to display the user profile')
@then(u'the website asks me to log in')
def step_impl(context):
raise NotImplementedError(u'STEP: Then the website asks me to log in')
Behave ha trovato il feature file, ma nessuna implementazione dei passi dello scenario. I passi sono funzioni Python con un argomento context
(e argomenti opzionali di parole chiave) che sono annotati con @given
, @when
o @then
, che prendono il testo del passo come argomento.
Behave cerca di far corrispondere le funzioni Python con il testo dei feature file e le esegue. La variabile context
viene usata per passare informazioni da un step all'altro, ad esempio si può allegare il risultato di un'attività nel passo @when
a questa variabile, e valutare il valore solo nel passo @then
, di seguito.
Scenario Outlines¶
Behave supporta anche la parametrizzazione dei test, che viene chiamata scenario outlines (abozzi) con examples (esempi). Possiamo quindi provare a implementare il nostro test unitario utilizzando Behave.
Feature: Calculate the surface of a square
Scenario Outline: Calculating the square of numbers
Given I have imported the calculator module
When I calculate the square of <length>
Then the result should be <surface>
Examples: Valid results
| length | surface |
| 2 | 4 |
| 0 | 0 |
| -1 | 1 |
Di seguito si può vedere una possibile implementazione. Questo codice deve trovarsi in un modulo Python, ad esempio features/steps/square.py
.
@given("I have imported the calculator module")
def step_impl(context):
from example import square
context.func = square
@when("I calculate the square of {length:d}")
def step_impl(context, length):
context.result = context.func(length)
@then("the result should be {surface:d}")
def step_impl(context, surface):
assert surface == context.result
I {...}
sono argomenti per le funzioni con un tipo di dati opzionale che viene valutato dal matcher. Behave supporta numerosi tipi di dati di base (vedere la documentazione di Behave). Si noti anche che Behave pensa a importare le funzioni di annotazione.
Quando si esegue behave
, si ottiene:
$ behave
Feature: Calculate the surface of a square # features/example.feature:1
Scenario Outline: Calculating the square of numbers -- @1.1 Valid results
Given I have imported the calculator module
When I calculate the square of 2
Then the result should be 4
Scenario Outline: Calculating the square of numbers -- @1.2 Valid results
Given I have imported the calculator module
When I calculate the square of 0
Then the result should be 0
Scenario Outline: Calculating the square of numbers -- @1.3 Valid results
Given I have imported the calculator module
When I calculate the square of -1
Then the result should be 1
1 feature passed, 0 failed, 0 skipped
3 scenarios passed, 0 failed, 0 skipped
9 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.000s