«1. Введение

Хуки Cucumber могут пригодиться, когда мы хотим выполнить определенные действия для каждого сценария или шага, но без явного указания этих действий в коде Gherkin.

В этом уроке мы рассмотрим хуки @Before, @BeforeStep, @AfterStep и @After Cucumber.

2. Обзор хуков в Cucumber

2.1. Когда следует использовать хуки?

Хуки можно использовать для выполнения фоновых задач, не являющихся частью бизнес-функций. Такими задачами могут быть:

    Запуск браузера Настройка или очистка файлов cookie Подключение к базе данных Проверка состояния системы Мониторинг

Примером использования для мониторинга может быть обновление информационной панели с ходом теста в режиме реального времени.

Хуки не видны в коде Gherkin. Поэтому мы не должны рассматривать их как замену огуречного фона или заданного шага.

Мы рассмотрим пример, в котором мы используем хуки для создания скриншотов во время выполнения теста.

2.2. Объем хуков

Хуки влияют на каждый сценарий. Поэтому рекомендуется определять все хуки в выделенном классе конфигурации.

Нет необходимости определять одни и те же хуки в каждом классе связующего кода. Если мы определим хуки в том же классе, что и наш связующий код, у нас будет менее читаемый код.

3. Хуки

Давайте сначала посмотрим на отдельные хуки. Затем мы рассмотрим полный пример, где мы увидим, как хуки выполняются при объединении.

3.1. @Before

Методы, аннотированные @Before, будут выполняться перед каждым сценарием. В нашем примере мы будем запускать браузер перед каждым сценарием:

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

Если мы аннотируем несколько методов с помощью @Before, мы можем явно определить порядок выполнения шагов:

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

вышеприведенный метод выполняется вторым, так как мы передаем 2 в качестве значения параметра порядка в аннотацию. Мы также можем передать 1 в качестве значения параметра порядка нашего метода инициализации:

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

Итак, когда мы выполняем сценарий, сначала выполняется initialization(), а потом — beforeScenario().

3.2. @BeforeStep

Методы, аннотированные @BeforeStep, выполняются перед каждым шагом. Давайте воспользуемся аннотацией, чтобы делать скриншоты перед каждым шагом:

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

3.3. @AfterStep

Методы, аннотированные @AfterStep, выполняются после каждого шага:

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

Здесь мы использовали @AfterStep, чтобы делать снимки экрана после каждого шага. Это происходит независимо от того, завершается шаг успешно или нет.

3.4. @After

Методы, аннотированные @After, выполняются после каждого сценария:

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

В нашем примере мы сделаем последний снимок экрана и закроем браузер. Это происходит независимо от того, успешно ли завершился сценарий.

3.5. Параметр сценария

Методы, аннотированные аннотацией ловушки, могут принимать параметр типа Scenario:

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

Объект типа Scenario содержит информацию о текущем сценарии. Включены имя сценария, количество шагов, имена шагов и статус (пройдено или не пройдено). Это может быть полезно, если мы хотим выполнять разные действия для пройденных и не пройденных тестов.

4. Выполнение хуков

4.1. Happy Flow

Давайте теперь посмотрим, что происходит, когда мы запускаем сценарий Cucumber со всеми четырьмя типами хуков:

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

Глядя на результат тестового запуска в IntelliJ IDE, мы видим порядок выполнения:

Сначала выполняются два наших хука @Before. Затем до и после каждого шага запускаются хуки @BeforeStep и @AfterStep соответственно. Наконец, запускается хук @After. Все хуки выполняются для обоих сценариев.

4.2. Несчастливый поток: шаг не пройден

Давайте посмотрим, что произойдет, если шаг не пройден. Как видно на снимке экрана ниже, выполняются хуки @Before и @After неудачного шага. Последующие шаги пропускаются, и, наконец, выполняется хук @After:

Поведение @After аналогично действию finally-clause после try-catch в Java. Мы могли бы использовать его для выполнения задач очистки, если шаг не удался. В нашем примере мы по-прежнему делаем снимок экрана, даже если сценарий не работает.

4.3. Несчастливый поток: хук не работает

«Давайте посмотрим, что происходит, когда выходит из строя сам хук. В приведенном ниже примере первый @BeforeStep терпит неудачу.

В этом случае фактический шаг не запускается, но запускается хук @AfterStep. Последующие шаги также не будут выполняться, тогда как хук @After выполняется в конце:

5. Условное выполнение с тегами

Хуки определяются глобально и влияют на все сценарии и шаги. Однако с помощью тегов Cucumber мы можем точно определить, для каких сценариев должен выполняться хук:

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

Этот хук будет выполняться только для сценариев, помеченных тегом @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

Мы можем добавить поддержку Cucumber Java 8, чтобы определить все хуки с лямбда-выражениями.

Вспомним наш хук инициализации из приведенного выше примера:

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

Переписанный с лямбда-выражением, мы получаем:

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

То же самое работает и для @BeforeStep, @After и @AfterStep.

7. Заключение

В этой статье мы рассмотрели, как определить хуки Cucumber.

Мы обсудили, в каких случаях их следует использовать, а когда нет. Затем мы увидели, в каком порядке выполняются хуки и как мы можем добиться условного выполнения.

Наконец, мы увидели, как можно определять хуки с помощью лямбда-нотации Java 8.

Как обычно, полный исходный код этой статьи доступен на GitHub.