Golang: тестирование программного обеспечения

Замените TDD на BDD: часть 3 — вот как это реализовать (продолжение)

Узнайте, как писать тесты Behavior Driven Development (BDD) с помощью веб-приложений Godog и Playwright для Go.

Введение

👉 Примечание. Это продолжение второй части серии тестовых статей BDD. Чтобы прочитать Часть I или Часть II, выберите один из вариантов ниже. В противном случае продолжим.





Краткое предисловие

Предпосылки

  • Go1.17
  • Понимание BDD

Что вы узнаете

Внедрение определений шагов (продолжение)

Реализация теста кликов пользователя

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

When I navigate to https://pkg.go.dev by clicking packages on menu

В приведенном выше шаге Когда огурец мы хотим реализовать тест кликов пользователя. То есть, когда пользователь нажимает на пакет в меню, он должен быть успешно перенаправлен в другое место. В данном случае мы хотим, чтобы они переходили на https://pkg.go.dev, наше веб-приложение.

Итак, давайте обновим нашу функцию iNavigateToHttpspkggodevByClickingPackagesOnMenu до кода ниже:

В нашей функции iNavigateToHttpspkggodevByClickingPackagesOnMenu (строка 3) мы используем объект context.Context для получения экземпляра playwright.Page, переданного на предыдущем шаге. Неудачный экземпляр страницы вернет ошибку.

В строке 8 мы используем метод thepage.Locator, чтобы найти элемент объектной модели документа (DOM) в веб-приложении (т. е. https://go.dev) с помощью выражения Xpath. Затем передаем XPath в пункт меню package на странице go.dev.

👉 Примечание. Если при поиске элемента возникнет ошибка, тест завершится неудачно. Кроме того, существуют другие методы страницы для получения элементов DOM, включая QuerySelector и QuerySelectorAll, для дальнейшего использования.

🎯 Совет для профессионалов. Получить выражение XPath для элемента может быть непросто, но если вам нужна помощь, не стесняйтесь использовать ChroPath (расширение Chrome)

Как только вы скопируете точное выражение XPath, вы захотите передать его page.Locator в виде строки, подобной приведенной ниже:

"xpath=//header/div[1]/nav[1]/div[1]/ul[1]/li[4]/a[1]"

Наша цель — найти элемент на странице DOM. И если есть ошибка, мы возвращаем ее.

Затем мы можем использовать метод locator.Click для имитации щелчка мыши по элементу, найденному на предыдущем шаге. Это применяет действие щелчка, чтобы перенаправить нас на pkg.go.devURL, который проверяется в строке 19. Если есть ошибка, мы возвращаем ее. .

Предполагая, что все предыдущие шаги были реализованы, мы возвращаем nil, чтобы указать, что они были выполнены успешно.

Теперь давайте снова запустим наш тест, и вы должны увидеть, что у нас есть 6 пройденных тестов:

3 scenarios (3 pending)
15 steps (6 passed, 3 pending, 6 skipped)

Использование заполнителя «‹package›»

Что касается следующего шага, вы увидите заполнитель (например, «‹package›») ниже, который позволит нам передать аргумент BDD-инфраструктуре Godog Cucumber. Для этого мы будем использовать двойные кавычки с параметром между ними:

And I enter "<package>" package name in the search

Заполнитель ‹package› в шаге выше указывает, что фактическое имя пакета (которое мы получаем из шага Gherkin Примеры;см. часть II) должно быть вставлено в шаг при его выполнении. .

💡 Большая идея. Этот шаг Gherkin указывает, что тест должен имитировать ввод указанного имени пакета в поле поиска на странице. Точные детали того, как это делается, описаны в разделе Определение шага Годога в Части II этой серии.

Использование locator.Fill для имитации набора текста

Теперь, когда это завершено, давайте посмотрим, как выглядит определение шага:

В строке 8 мы используем метод page.Locator для поиска входного элемента с помощью выражения XPath, затем переходим к использованию метода locator.Fill.

locator.Fill ожидает готовности элемента формы и имитирует ввод указанного имени пакета в поле ввода, которое было передано функции iEnterPackageNameInTheSearch. Если при заполнении поля возникает ошибка, мы возвращаем эту ошибку.

Вы видели, как Драматург ввел имя пакета в поисковую строку браузера?

Вы не должны были — давайте обновим нашу функцию, добавив этот код над строкой 18:

time.Sleep(5*time.Second)

Функция time.Sleep используется для задержки нашего текущего goroutine на 5 секунд. Это позволяет нам увидеть, как Playwright взаимодействует с браузером. Если мы снова запустим наш тест, мы увидим, что ввод заполнен переданным именем пакета.

Теперь, когда это сделано, давайте отменим последнее изменение, в котором мы добавили нашу функцию time.Sleep, и перейдем к предпоследнему шагу, прежде чем мы снова запустим наш тест.

And I press search button

Применение действия клика

Теперь нам просто нужно найти элемент кнопки поиска (относительно шага Gherkin And выше) и применить к нему действие щелчка:

Остальная часть кода аналогична определениям предыдущего шага. Однако в строке 13, после нахождения кнопки поиска с выражением XPath (строка 8), мы используем метод locator.Click для имитации нажатия пользователем кнопки, когда она готова на странице (который возвращает nil в случае успеха).

👉 Примечание. В противном случае мы возвращаем ошибку

Если мы снова запустим наш тест, разве мы не сможем увидеть действие поиска в браузере и просмотреть страницу результатов поиска?

К сожалению нет. Тем не менее, мы можем снова использовать метод time.Sleep для просмотра результата перед возвратом nil.

Если вы открыты для этого, попробуйте — вы должны получить результат, подобный этому:

3 scenarios (3 pending)
15 steps (12 passed, 3 pending)

Возврат результата поиска пакета

На данный момент мы выполнили 12 успешных шагов; теперь давайте реализуем наше окончательное определение шага корнишона, которое проверит, успешен ли наш поиск:

Then I should see a search page with "<packageUrl>" package

Давайте посмотрим на реализацию определения шага:

Функция iShouldSeeASearchPageWithPackage утверждает и подтверждает, что наше веб-приложение может вернуть результат поиска пакета, используя переданный ему URL-адрес пакета.

В строке 8 мы используем метод page.QuerySelectorAll для поиска всех элементов на странице с классом SearchSnippet-headerContainer. Если возникает ошибка, функция возвращает ее.

В строке 13 мы объявляем переменную с именем isAvailable, которая служит переключателем для определения того, был ли найден переданный URL-адрес.

Мы также перебираем каждый из элементов в результатах query, ища элемент с тегом h2 с тегом дочернего элемента a. На странице поиска это название пакета. Функция возвращает ошибку, если она возникает.

Если мы находим titleElement, как мы видим в строке 20, мы используем метод TextContent объекта элемента для получения текста элемента, который должен быть заголовком пакета и URL-адресом. Опять же, функция вернет здесь ошибку, если она есть.

В строке 25 мы проверяем, содержит ли заголовок пакета URL-адрес пакета, который был передан функции. Если это так, мы устанавливаем переменную isAvailable в true , что раньше прерывает цикл. Конечно, если цикл завершится без совпадения, isAvailable останется false.

В строке 31 мы проверяем, является ли isAvailable false, и возвращаем ошибку, указывающую, что пакет не найден на странице результатов поиска. Однако, если это true, мы возвращаем nil, что означает, что пакет найден.

Один последний запуск

Давайте запустим наше приложение еще раз, что должно дать нам следующее:

--- Failed steps:

  Scenario Outline: Search package on https://pkg.go.dev # features/searchPackages.feature:7
    Then I should see a search page with "github.com/cucumber/godog" package # features/searchPackages.feature:11
      Error: package github.com/cucumber/godog is not available

  Scenario Outline: Search package on https://pkg.go.dev # features/searchPackages.feature:7
    Then I should see a search page with "github.com/joho/godotenv" package # features/searchPackages.feature:11
      Error: package github.com/joho/godotenv is not available

  Scenario Outline: Search package on https://pkg.go.dev # features/searchPackages.feature:7
    Then I should see a search page with "github.com/marvinhosea/filter" package # features/searchPackages.feature:11
      Error: package github.com/marvinhosea/filter is not available


3 scenarios (3 failed)
15 steps (12 passed, 3 failed)
20.665271125s

👉 Примечание: (я извлек только важную часть вывода)

Чего ждать? Наш тест… провалился?

Что ж, если мы отладим наше определение шага Godog iShouldSeeASearchPageWithPackage, мы обнаружим, что Playwright не удалось найти элементы результатов поиска.

🎯 Совет для профессионалов. Это обычное явление, когда элемент не найден в модели DOM. Чтобы исправить это, нам нужно дождаться загрузки элемента

Давайте добавим следующий код над строкой 8 и запустим тесты еще раз:

var timeOut float64 = 2000
 _, err := page.WaitForSelector(".SearchSnippet-headerContainer", playwright.PageWaitForSelectorOptions{
  Timeout: &timeOut,
 })

Вуаля!

3 scenarios (3 passed)
15 steps (15 passed)
20.634797041s

Окончательный код

Вот как должен выглядеть окончательный код:

Исходный код



Заключение

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

По большому счету, BDD помогает каждому понять, что программное обеспечение «должно делать», представляя его в простом для понимания формате. Это улучшает сплоченность команды и сотрудничество, глубину документации, эффективность в долгосрочной перспективе и многое другое.

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

  • Интегрируйте тесты BDD с CI/CD
  • Создавайте отчеты для тестов BDD с помощью таких инструментов, как Allure.
  • Запустите тесты BDD из Go test
  • И т. д.

Основные выводы

  • С помощью BDD Gherkin технические и не технические специалисты могут более эффективно общаться и сотрудничать.
  • Написание тестов BDD позволяет разработчикам создавать готовый к поставке функциональный продукт, который дает им представление о том, как пользователи будут использовать приложение с высоты птичьего полета.
  • Тесты BDD улучшают процесс выпуска и поток DevOps, особенно для небольших команд.
  • Тесты BDD улучшают качество кода, сокращают количество переделок, улучшают проектную документацию и снижают как проектные риски, так и затраты на обслуживание.

Рекомендации по использованию BDD

  • Пишите сценарии поведения приложений простым языком, чтобы бизнес-аналитики, владельцы продуктов, тестировщики и разработчики могли их понять (и, таким образом, лучше сотрудничать).
  • Используйте единый формат для написания примеров (например, Дано-Когда-Тогда).
  • Держите примеры сфокусированными и конкретными и избегайте использования слишком большого количества деталей (или пограничных случаев) в одном тесте.
  • Исправьте проблемы функционального кода, пока не будет достигнуто желаемое поведение, прежде чем переходить к следующему шагу или сценарию.
  • Рефакторинг кода, чтобы его было легче читать и повторно использовать в реализации теста BDD.
  • Регулярно просматривайте и обновляйте тесты BDD, чтобы они продолжали точно отражать поведение приложения.
  • 🚀 Бонус: используйте автоматизацию для выполнения тестов и/или включите тестирование BDD в рабочий процесс CI/CD, чтобы сэкономить время и гарантировать согласованность

Тестирование BDD: другие статьи серии





Раскрытие информации: в соответствии с правилами и рекомендациями Medium.com я публично подтверждаю финансовую компенсацию от UniDoc за эту статью. Все мысли, мнения, код, изображения, записи и т. д. принадлежат мне.