Разделы портала

Онлайн-тренинги

.
Начните автоматизировать UI, используя SpecFlow
18.03.2022 00:00

Автор: Луиза Гиббс (Louise Gibbs)
Оригинал статьи
Перевод: Ольга Алифанова

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

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

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

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

В этом примере я расскажу, как я начинаю совершенно новый проект UI-автоматизации.

Предварительные шаги: настройка SpecFlow и Visual Studio

Примеры в этой статье взяты из тестов, разработанных на SpecFlow в Visual Studio. Код написан на C#.

В секции полезных ссылок есть ссылка на мой репозиторий GitHub, где находится ряд примеров тестов SpecFlow. Ими можно руководствоваться, создавая собственные решения, или попрактиковаться, добавляя собственные тесты и привыкая к структуре, описанной в этой статье. Об этом я подробнее поговорю в третьей части.

После создания проекта (или использования моего проекта из GitHub) вам нужно установить ряд пакетов NuGet. Это можно сделать через Tools > NuGet Package Manager > Manage NuGet Package Manager for Solution.

Я установила следующие пакеты NuGet:

  • Microsoft.Extensions.Configuration.Json
  • Microsoft.NET.Test.Sdk
  • Selenium.Support
  • Selenium.WebDriver
  • Selenium.WebDriver.ChromeDriver
  • Specflow
  • Specflow.Tools.MsBuild.Generation
  • SpecFlow.xUnit
  • Xunit
  • Xunit.core
  • Xunit.runner.visualstudio

Вам также понадобится это расширение, которое можно установить через Tools > Extensions and Updates.

  • SpecFlow for Visual Studio 2017

Шаг 1 – запустите приложение, используя автоматизацию

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

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

Код ниже запускает Google Chrome, переходит к нужной странице (GoToUrl) и максимизирует экран (Window.Maximise()), чтобы вы могли видеть, что происходит в браузере, и чтобы все тесты стартовали на заранее известном размере браузера.

public static IWebDriver Driver { get; set; }
 
public static void InitializeTest()
{
     Driver = new ChromeDriver(Environment.CurrentDirectory);
     Driver.Navigate().GoToUrl("https://automationintesting.online/");
     Driver.Manage().Window.Maximize();
}

В Visual Studio можно добавлять к методам атрибуты. Атрибуты можно использовать для применения особого свойства или характеристики к классу. Их можно добавлять в начале класса или метода внутри квадратных скобок. При создании тестов SpecFlow атрибуты используются для применения шагов сценария к определенному методу (я подробнее расскажу об этом на шаге 3, когда мы будем создавать привязку шагов). Атрибуты также можно использовать для объявления, какой метод должен запускаться до и после каждого сценария без необходимости добавлять к каждому сценарию такой шаг.

Атрибуты [BeforeScenario] и [AfterScenario] обозначают код, который нужно запускать до и после прогона сценария. В этом случае будет запускаться метод InitializeTest(), открывающий Chrome и переходящий на страницу. После прогона теста драйвер закроет окно браузера. Это предотвратит открытие множества окон, остающихся после каждого теста.

[BeforeScenario]
public void StartScenario()
{
     InitializeTest();
}
 
[AfterScenario]
public void AfterScenario()
{
      TestUtilities.Driver.Close();
}

Шаг 2 – основной тест-сценарий

В SpecFlow вместо тестов у нас "сценарии". Эти сценарии используют синтаксис Gherkin, где каждый шаг начинается со слов "Если", "Когда" и "Тогда". Больше информации о настройке сценариев SpecFlow с использованием синтаксиса Gherkin можно найти по ссылке.

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

Вот так может выглядеть этот сценарий:

Сценарий: заполнение формы обратной связи

Когда я отправляю данные через форму контактов

Тогда я должна получить сообщение, что форма была отправлена.

В SpecFlow фиолетовый текст означает, что шаг не найден (мы еще не создали эти шаги – мы сделаем это в третьей части). Пока что это нормально, тест будет запускаться, но упадет, так как не найдет привязанных к шагам методов.

Шаг 3 – создание привязки шагов сценария

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

При нажатии на "Да" код, требуемый для создания шага, будет скопирован в буфер обмена (это бережет кучу времени, когда вы привязываете множество шагов!)


Вставив код, вы увидите что-то вроде этого:

[When(@"I submit some details in the contact details form")]
public void WhenISubmitSomeDetailsInTheContactDetailsForm()
{
     ScenarioContext.Current.Pending();
}

Если вы вернетесь к сценарию SpecFlow, то шаг станет белым или черным (в зависимости от темной или светлой темы приложения). Тест будет продолжать падать – все еще нужно добавить настоящий код к методу, но теперь тесту есть, что искать, прогоняя этот шаг.

Это нужно сделать для каждого непривязанного шага в сценарии.

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

Класс, в который вы вставляете код, должен содержать атрибут [Binding]. Начало класса будет выглядеть примерно так:

[Binding]
public sealed class ContactUsSteps
     {

Шаг 4 – настройка локаторов.

Перед созданием кода для каждого шага нужно настроить локаторы.

Локаторы используются для поиска появляющихся на странице элементов. Без них мы не можем взаимодействовать с элементами страницы.

Я хочу записать список элементов, с которыми мне нужно взаимодействовать на каждом шаге.

Для формы обратной связи нужно настроить локатор для каждого текстового поля на форме, а также для кнопки отправки.


Если кликнуть по элементу правой кнопкой и нажать "Инспектировать", вы увидите информацию об этом элементе в DevTools:

 

Воспользуемся функцией FindElement() для поиска конкретного xpath.

Xpath должен быть в строго определенном формате:

“//tagname[@Attribute=’value’]”

Если мы пытаемся найти конкретный элемент, то имя тега – это первое слово в коде элемента. К примеру, это может быть ‘form’, ‘input’ или ‘div’. Атрибутом может быть что угодно, назначенное элементу – например, 'text' или 'class'. Значение должно соответствовать значению атрибута этого элемента.

Можно искать конкретный элемент, а затем попытаться найти элемент внутри этого элемента. Для этого можно добавить дополнительные xpath в конце другого xpath.

Вот локаторы, которые я настроила, используя информацию из DevTools.

public IWebElement ContactSection => Driver.FindElement(By.XPath(".//div[@class='row contact']//div[@class='col-sm-5']"));
 
public IWebElement FormSection => ContactSection.FindElement(By.XPath("//form"));
public IWebElement NameTextBox => FormSection.FindElement(By.Id("name"));
public IWebElement EmailTextBox => FormSection.FindElement(By.Id("email"));
public IWebElement PhoneTextBox => FormSection.FindElement(By.Id("phone"));
public IWebElement SubjectTextBox => FormSection.FindElement(By.Id("subject"));
public IWebElement MessageTextBox => FormSection.FindElement(By.Id("description"));
public IWebElement SubmitButton => FormSection.FindElement(By.Id("submitContact"));

В первом примере, ‘ContactSection’, мы ищем элемент с тегом 'div' и атрибутом 'class', равным 'row contact'. Дополнительный xpath добавлен в конце оригинального xpath и ищет другой элемент внутри первого элемента. У этого второго элемента тег 'div' и атрибут 'class', равный 'col-sm-5'.

public IWebElement ContactSection => Driver.FindElement(By.XPath(".//div[@class='row contact']//div[@class='col-sm-5']"));

Следующий элемент, FormSection, также существует внутри ContactSection. Вместо того, чтобы искать по всей странице, мы ищем только внутри ContactSection. В ней только одна форма, поэтому нужно найти элемент с тегом 'form'.

public IWebElement FormSection => ContactSection.FindElement(By.XPath("//form"));

Избегание чересчур длинных xpath улучшает поддерживаемость тестов в будущем. Это также снижает количество дупликации кода. Если бы я использовала один xpath для элемента FormSection, он бы выглядел так:

".//div[@class='row contact']//div[@class='col-sm-5']//form"

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

Следующий локатор, настроенный с использованием ID, тоже можно настроить через xpath. Любой из примеров ниже найдет один и тот же элемент.

FormSection.FindElement(By.Id("name"));
FormSection.FindElement(By.XPath("//input[@id=’name’]"));

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

Всегда стоит поэкспериментировать с разными xpath и подумать над альтернативными стратегиями для локаторов – например, CSS-селекторами. Ссылки на ряд полезных чит-листов находятся в разделе ресурсов, и там есть информация, как настроить локаторы с использованием XPath и селекторов CSS.

Шаг 5 – как писать код для шагов сценария, используя локаторы

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

Мы можем вставить текст в текстовое поле, взяв элемент и отправляя нажатия клавиш:

NameTextBox.SendKeys("Louise");

Мы можем кликнуть по кнопке, взяв элемент и кликнув по нему:

SubmitButton.Click();

Нам нужно только добавить эти строки кода к привязке шагов. Вот полный код для шага, в котором мы заполняем форму обратной связи:

[When(@"I submit some details in the contact details form")]
public void WhenISubmitSomeDetailsInTheContactDetailsForm()
{
     NameTextBox.SendKeys("Louise");
     EmailTextBox.SendKeys(" Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript ");
     PhoneTextBox.SendKeys("01234567890");
     SubjectTextBox.SendKeys("Subject");
     MessageTextBox.SendKeys("This is a message about booking a room");
 
     SubmitButton.Click();
}

Шаг 6 – убеждаемся, что тест пройден

Следующий шаг нашего теста – это подтверждение, что форма успешно отправлена. Так как эта статья посвящена UI-тестам, мы убедимся, что на экране появилось сообщение. Это важный шаг, потому что если он неверен, это снижает ценность теста.

Чтобы убедиться, что тест пройден, мы проверим, что сообщение "Thanks for getting in touch" появилось на странице после того, как пользователь отправил форму.


Для создания этого шага следуем тому же алгоритму, что и для шага по заполнению формы.

1. Создаем      привязку шагов:
          [Then(@"I should be told that the form was submitted")]
          public void ThenIShouldBeToldThatTheFormWasSubmitted()
          {
         ScenarioContext.Current.Pending();
          }
2. Настраиваем локатор.
         Для этого нам нужен заголовок сообщения, появляющегося в секции обратной связи:
         public IWebElement HeaderText => ContactSection.FindElement(By.XPath(".//h2"));
3. Пишем код для шага, используя локаторы
        [Then(@"I should be told that the form was submitted")]
         public void ThenIShouldBeToldThatTheFormWasSubmitted()
        {
       Assert.Contains("Thanks for getting in touch", HeaderText.Text);
       }

Альтернативным способом убедиться, что сообщение успешно отправлено, может быть запрос к API или базе данных для проверки, что передана верная информация. Можно также авторизоваться в админ-панели и проверить, что форма появилась в списке сообщений. Можно еще добавить более тщательные проверки – что в сообщении употреблено правильное имя, и что сообщение целиком (а не только его заголовок) соответствуют ожиданиям. Начиная с самых простых проверок и заставляя их работать, можно расширять и улучшать тест в будущем.

Заключение

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

Я следую этому подходу, даже если меня просят поработать над уже устоявшимся проектом. Настройка простых тестов – отличный способ разобраться в коде. Одно из преимуществ SpecFlow – наличие готовой инфраструктуры. К примеру, я начинаю с создания простых тестов, используя различные функции и методы, которые уже написаны. Первые созданные вами тесты могут не войти в финальный вариант, но первичное знакомство сильно упрощает разработку и поддержку более сложных тестов.

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

Полезные ресурсы

Ссылка на мой репозиторий GitHub. Там находится ряд базовых тестов, которые я писала для сайта RestfulBookerPlatform.

https://github.com/LouiseJGibbs/RestfulBooker

Сайт RestfulBookerPlatform, полезный сайт для практики настройки автотестов UI:

https://automationintesting.online/

Сайт SpecFlow с полезными ресурсами по настройке сценариев:

https://specflow.org/

Дополнительная информация о синтаксисе Gherkin в сценариях SpecFlow:

https://specflow.org/bdd/gherkin/

XPath, чит-лист

https://devhints.io/xpath

CSS-селекторы, чит-лист

https://www.freecodecamp.org/news/css-selectors-cheat-sheet/

Обсудить в форуме