Gurkenhaken

1. Einleitung

Gurkenhaken können nützlich sein, wenn wir für jedes Szenario oder jeden Schritt bestimmte Aktionen ausführen möchten, ohne diese Aktionen jedoch explizit im Gurkencode zu haben.

In diesem Tutorial werden die Hooks @Before , @BeforeStep, @AfterStep und @After Cucumber beschrieben.

2. Übersicht der Haken in Gurke

2.1. Wann sollten Haken verwendet werden?

Hooks können verwendet werden, um Hintergrundaufgaben auszuführen, die nicht Teil der Geschäftsfunktionalität sind. Solche Aufgaben könnten sein:

  • Browser starten
  • Cookies setzen oder löschen
  • Verbindung zu einer Datenbank herstellen
  • Überprüfen des Systemstatus
  • Überwachung

Ein Anwendungsfall für die Überwachung wäre das Aktualisieren eines Dashboards mit dem Testfortschritt in Echtzeit.

Haken sind im Gurkencode nicht sichtbar. Daher sollten wir sie nicht als Ersatz für einen Gurkenhintergrund oder einen bestimmten Schritt betrachten .

Wir werden uns ein Beispiel ansehen, in dem wir Hooks verwenden, um während der Testausführung Screenshots zu machen.

2.2. Umfang der Haken

Hooks wirken sich auf jedes Szenario aus. Daher empfiehlt es sich, alle Hooks in einer dedizierten Konfigurationsklasse zu definieren.

Es ist nicht erforderlich, in jeder Klebercodeklasse dieselben Haken zu definieren. Wenn wir mit unserem Klebercode Hooks in derselben Klasse definieren, haben wir weniger lesbaren Code.

3. Haken

Schauen wir uns zunächst die einzelnen Haken an. Wir werden uns dann ein vollständiges Beispiel ansehen, in dem wir sehen werden, wie Hooks in Kombination ausgeführt werden.

3.1. @Vor

Mit @Before kommentierte Methoden werden vor jedem Szenario ausgeführt . In unserem Beispiel starten wir den Browser vor jedem Szenario:

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

Wenn wir mehrere Methoden mit @Before kommentieren , können wir die Reihenfolge, in der die Schritte ausgeführt werden, explizit definieren:

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

Die obige Methode wird als zweites ausgeführt, da wir 2 als Wert für den order- Parameter an die Annotation übergeben. Wir können auch 1 als Wert für den Ordnungsparameter unserer Initialisierungsmethode übergeben:

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

Wenn wir also ein Szenario ausführen, wird initialization () zuerst und beforeScenario () als zweites ausgeführt.

3.2. @BeforeStep

Mit @BeforeStep annotierte Methoden werden vor jedem Schritt ausgeführt . Verwenden wir die Anmerkung, um vor jedem Schritt einen Screenshot zu erstellen:

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

3.3. @ AfterStep

Mit @AfterStep kommentierte Methoden werden nach jedem Schritt ausgeführt :

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

Wir haben @AfterStep hier verwendet, um nach jedem Schritt einen Screenshot zu machen. Dies geschieht unabhängig davon, ob der Schritt erfolgreich abgeschlossen wurde oder fehlschlägt .

3.4. @Nach

Mit @After annotierte Methoden werden nach jedem Szenario ausgeführt :

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

In unserem Beispiel machen wir einen letzten Screenshot und schließen den Browser. Dies geschieht unabhängig davon, ob das Szenario erfolgreich abgeschlossen wurde .

3.5. Der Szenario- Parameter

Die mit einer Hook-Annotation versehenen Methoden können einen Parameter vom Typ Szenario akzeptieren :

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

Das Objekt vom Typ Szenario enthält Informationen zum aktuellen Szenario. Enthalten sind der Name des Szenarios, die Anzahl der Schritte, die Namen der Schritte und der Status (bestanden oder nicht bestanden). Dies kann nützlich sein, wenn wir verschiedene Aktionen für bestandene und fehlgeschlagene Tests ausführen möchten.

4. Hook-Ausführung

4.1. Glücklicher Fluss

Schauen wir uns nun an, was passiert, wenn wir ein Gurkenszenario mit allen vier Arten von Hooks ausführen:

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

Wenn wir uns das Ergebnis eines Testlaufs in der IntelliJ IDE ansehen, sehen wir die Ausführungsreihenfolge:

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.

Schließlich haben wir gesehen, wie wir Hooks mit Java 8 Lambda-Notation definieren können.

Wie üblich ist der vollständige Quellcode dieses Artikels auf GitHub verfügbar.