«1. Обзор

В этом коротком уроке мы познакомимся с Cucumber Backgrounds, функцией, которая позволяет нам выполнять несколько предложений для каждого теста Cucumber Feature.

2. Огуречный фон

Во-первых, давайте объясним, что такое огуречный фон. Его цель — выполнить одно или несколько предложений перед каждым тестом функции.

Но какую проблему мы здесь пытаемся решить?

Допустим, у нас есть приложение для книжного магазина, которое мы хотим протестировать с помощью Cucumber. Прежде всего, давайте создадим это приложение, которое будет просто классом Java:

public class BookStore {
    private List<Book> books = new ArrayList<>();
    
    public void addBook(Book book) {
        books.add(book);
    }
    
    public List<Book> booksByAuthor(String author) {
        return books.stream()
          .filter(book -> Objects.equals(author, book.getAuthor()))
          .collect(Collectors.toList());
    }

    public Optional<Book> bookByTitle(String title) {
        return books.stream()
          .filter(book -> book.getTitle().equals(title))
          .findFirst();
    }
}

Как мы видим, можно добавлять и искать книги в магазине. Теперь давайте создадим несколько предложений Cucumber для взаимодействия с книжным магазином:

public class BookStoreRunSteps {
    private BookStore store;
    private List<Book> foundBooks;
    private Book foundBook;
    
    @Before
    public void setUp() {
        store = new BookStore();
        foundBooks = new ArrayList<>();
    }
    
    @Given("^I have the following books in the store$")
    public void haveBooksInTheStore(DataTable table) {
        List<List<String>> rows = table.asLists(String.class);

        for (List<String> columns: rows) {
            store.addBook(new Book(columns.get(0), columns.get(1)));
        }
    }
    
    @When("^I search for books by author (.+)$")
    public void searchForBooksByAuthor(String author) {
        foundBooks = store.booksByAuthor(author);
    }

    @When("^I search for a book titled (.+)$")
    public void searchForBookByTitle(String title) {
        foundBook = store.bookByTitle(title).orElse(null);
    }
    
    @Then("^I find (\\d+) books$")
    public void findBooks(int count) {
        assertEquals(count, foundBooks.size());
    }

    @Then("^I find a book$")
    public void findABook() {
        assertNotNull(foundBook);
    }

    @Then("^I find no book$")
    public void findNoBook() {
        assertNull(foundBook);
    }
}

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

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

Feature: Book Store Without Background
  Scenario: Find books by author
    Given I have the following books 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 |
    When I search for books by author Erik Larson
    Then I find 2 books

  Scenario: Find books by author, but isn't there
    Given I have the following books 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 |
    When I search for books by author Marcel Proust
    Then I find 0 books

  Scenario: Find book by title
    Given I have the following books 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 |
    When I search for a book titled The Lion, the Witch and the Wardrobe
    Then I find a book

  Scenario: Find book by title, but isn't there
    Given I have the following books 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 |
    When I search for a book titled Swann's Way
    Then I find no book

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

3. Пример

Итак, как создать фон, создающий магазин для этой функции? Чтобы сделать это, мы должны использовать ключевое слово Фон, дать ему название, как мы делаем для Сценария, и определить предложения для выполнения:

Background: The Book Store
  Given I have the following books 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: Find books by author
  When I search for books by author Erik Larson
  Then I find 2 books

Scenario: Find books by author, but isn't there
  When I search for books by author Marcel Proust
  Then I find 0 books

Scenario: Find book by title
  When I search for a book titled The Lion, the Witch and the Wardrobe
  Then I find a book

Scenario: Find book by title, but isn't there
  When I search for a book titled Swann's Way
  Then I find no book

Как мы видим, сценарии намного короче, чем раньше, а оставшиеся предложения сосредоточены на том, что мы пытаемся протестировать, а не на настройке данных.

4. Разница с @Before

Теперь давайте обсудим разницу между огуречным фоном и хуком @Before. Хук также позволяет нам выполнять код перед сценарием, но этот код скрыт от тех, кто только читает файлы функций. С другой стороны, фон состоит из предложений, которые видны в файлах функций.

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

В этой короткой статье мы узнали, как использовать функцию огуречного фона. Это позволяет нам выполнять несколько предложений перед каждым сценарием функции. Мы также обсудили разницу между этой функцией и хуком @Before.

Как обычно, код для этой статьи можно найти на GitHub.