Ganci per cetriolo

1. Introduzione

Gli hook Cucumber possono tornare utili quando vogliamo eseguire azioni specifiche per ogni scenario o passaggio, ma senza avere queste azioni esplicitamente nel codice Gherkin.

In questo tutorial, esamineremo gli hook @Before , @BeforeStep, @AfterStep e @After Cucumber.

2. Panoramica dei ganci in cetriolo

2.1. Quando dovrebbero essere usati i ganci?

Gli hook possono essere utilizzati per eseguire attività in background che non fanno parte della funzionalità aziendale. Tali compiti potrebbero essere:

  • Avvio di un browser
  • Impostazione o cancellazione dei cookie
  • Connessione a un database
  • Verifica dello stato del sistema
  • Monitoraggio

Un caso d'uso per il monitoraggio potrebbe essere l'aggiornamento di un dashboard con l'avanzamento del test in tempo reale.

I ganci non sono visibili nel codice Gherkin. Pertanto, non dovremmo vederli come un sostituto per uno sfondo di cetriolo o un dato passaggio .

Vedremo un esempio in cui utilizziamo gli hook per acquisire schermate durante l'esecuzione del test.

2.2. Portata dei ganci

I ganci influenzano ogni scenario. Pertanto, è buona norma definire tutti gli hook in una classe di configurazione dedicata.

Non è necessario definire gli stessi hook in ogni classe di codice colla. Se definiamo hook nella stessa classe con il nostro codice glue, avremmo codice meno leggibile.

3. Ganci

Diamo prima un'occhiata ai singoli ganci. Vedremo quindi un esempio completo in cui vedremo come vengono eseguiti gli hook quando combinati.

3.1. @Prima

I metodi annotati con @Before verranno eseguiti prima di ogni scenario . Nel nostro esempio, avvieremo il browser prima di ogni scenario:

@Before public void initialization() { startBrowser(); }

Se annotiamo diversi metodi con @Before , possiamo definire esplicitamente l'ordine in cui vengono eseguiti i passaggi:

@Before(order=2) public void beforeScenario() { takeScreenshot(); }

Il metodo precedente viene eseguito per secondo, poiché si passa 2 come valore per il parametro order all'annotazione. Possiamo anche passare 1 come valore per il parametro order del nostro metodo di inizializzazione:

@Before(order=1) public void initialization()

Quindi, quando eseguiamo uno scenario, initialization () viene eseguito per primo e beforeScenario () viene eseguito per secondo.

3.2. @BeforeStep

I metodi annotati con @BeforeStep vengono eseguiti prima di ogni passaggio . Usiamo l'annotazione per acquisire uno screenshot prima di ogni passaggio:

@BeforeStep public void beforeStep() { takeScreenshot(); }

3.3. @AfterStep

I metodi annotati con @AfterStep vengono eseguiti dopo ogni passaggio :

@AfterStep public void afterStep() { takeScreenshot(); }

Abbiamo usato @AfterStep qui per fare uno screenshot dopo ogni passaggio. Ciò accade indipendentemente dal fatto che il passaggio termini correttamente o fallisca .

3.4. @Dopo

I metodi annotati con @After vengono eseguiti dopo ogni scenario :

@After public void afterScenario() { takeScreenshot(); closeBrowser(); }

Nel nostro esempio, faremo uno screenshot finale e chiuderemo il browser. Ciò accade indipendentemente dal fatto che lo scenario si concluda correttamente .

3.5. Il parametro dello scenario

I metodi annotati con un'annotazione hook possono accettare un parametro di tipo Scenario :

@After public void beforeScenario(Scenario scenario) { // some code }

L'oggetto di tipo Scenario contiene informazioni sullo scenario corrente. Sono inclusi il nome dello scenario, il numero di passaggi, i nomi dei passaggi e lo stato (superato o non superato). Questo può essere utile se vogliamo eseguire azioni diverse per i test superati e falliti.

4. Esecuzione del gancio

4.1. Flusso felice

Vediamo ora cosa succede quando eseguiamo uno scenario Cucumber con tutti e quattro i tipi di hook:

Feature: Book Store With Hooks Background: The Book Store Given The following books are available in the store | The Devil in the White City | Erik Larson | | The Lion, the Witch and the Wardrobe | C.S. Lewis | | In the Garden of Beasts | Erik Larson | Scenario: 1 - Find books by author When I ask for a book by the author Erik Larson Then The salesperson says that there are 2 books Scenario: 2 - Find books by author, but isn't there When I ask for a book by the author Marcel Proust Then The salesperson says that there are 0 books

Guardando il risultato di un test eseguito nell'IDE IntelliJ, possiamo vedere l'ordine di esecuzione:

First, our two @Before hooks execute. Then before and after every step, the @BeforeStep and @AfterStep hooks run, respectively. Finally, the @After hook runs. All hooks execute for both scenarios.

4.2. Unhappy Flow: a Step Fails

Let's see what happens if a step fails. As we can see in the screenshot below, both the @Before and @After hooks of the failing step are executed. The subsequent steps are skipped, and finally, the @After hook executes:

The behavior of @After is similar to the finally-clause after a try-catch in Java. We could use it to perform clean-up tasks if a step failed. In our example, we still take a screenshot even if the scenario fails.

4.3. Unhappy Flow: a Hook Fails

Let's look at what happens when a hook itself fails. In the example below, the first @BeforeStep fails.

In this case, the actual step doesn't run, but it's @AfterStep hook does. Subsequent steps won't run either, whereas the @After hook is executed at the end:

5. Conditional Execution with Tags

Hooks are defined globally and affect all scenarios and steps. However, with the help of Cucumber tags, we can define exactly which scenarios a hook should be executed for:

@Before(order=2, value="@Screenshots") public void beforeScenario() { takeScreenshot(); }

This hook will be executed only for scenarios that are tagged with @Screenshots:

@Screenshots Scenario: 1 - Find books by author When I ask for a book by the author Erik Larson Then The salesperson says that there are 2 books

6. Java 8

We can add Cucumber Java 8 Support to define all hooks with lambda expressions.

Recall our initialization hook from the example above:

@Before(order=2) public void initialization() { startBrowser(); }

Rewritten with a lambda expression, we get:

public BookStoreWithHooksRunSteps() { Before(2, () -> startBrowser()); }

The same also works for @BeforeStep, @After, and @AfterStep.

7. Conclusion

In this article, we looked at how to define Cucumber hooks.

We discussed in which cases we should use them and when we should not. Then, we saw in which order hooks execute and how we can achieve conditional execution.

Infine, abbiamo visto come si potrebbero definire gli hook con la notazione lambda Java 8.

Come al solito, il codice sorgente completo di questo articolo è disponibile su GitHub.