Введение
Всем Buenos Dias! В своей статье я хотел бы максимально лаконично и просто рассказать о том, как построить процесс автоматизированного тестирования web-приложения с нуля. Первым делом нужно правильно расставить приоритеты и выбрать приемлемое соотношение цена/качество. Сразу определимся — это будет не решение «на коленках» из зоопарка скриптов, которыми часто пользуются при ручном тестировании. В тоже время мы не будем тратить много усилий на проектирование нашего «фреймворка» для автоматизации. Наша цель — предоставить результаты своей бурной деятельности перед руководством в максимально короткие сроки, при этом система должна быть:
- максимально простой, чтобы тесты могли писать даже специалисты по ручному тестированию
- гибкой и расширяемой, поскольку мы не можем адекватно оценить весь объем работ на данном этапе
- кроссплатформенной (Selenium WebDriver C# поддерживает Firefox, Chrome и IE)
В своем примере я буду успользовать .NET (Microsoft Unit Testing Framework) и Selenium WebDriver C#.
Ссылки
Часть 1: Введение
Часть 2.1: Selenium API wrapper — Browser
Часть 2.2: Selenium API wrapper — WebElement
Часть 3: WebPages — описываем страницы
Часть 4: Наконец-то пишем тесты
Публикация фреймворка
Поехали
Итак, первым делом необходимо отобрать некоторое количество тестовых сценариев высокого приоритета, но довольно простых.
Далее создадим в студии новый solution. Вполне логично будет создать в нем 3 проекта: тесты, описание страниц и утилиты. Это и будут наши три базовые сущности.
Схема будет довольно простая: тест работает со страницами, запрашивая на них какие-либо данные или выполняя там какие-либо действия. В утилитах мы разместим классы, которые будут отвечать за работу c браузером и web-элементами на страницах посредством Selenium WebDriver. Вполне логично написать обертки (wrapper), поскольку Selenium WebDriver API имеет множество недостатков и может показаться довольно неудобным. Именно в этих обертках мы инкапсулируем (спрячем) весь специфический и некрасивый код. Для примера, создадим классы Browser и WebElement, которые предоставят разработчикам автотестов только тот футкционал, который им нужен. В дальнейшем я хотел бы описать этот процесс в отдельной статье, поэтому не буду останавливаться.
Тесты
Определимся с тем, что будут представлять собой наши тесты. Не будем изобретать велосипед — в идеале тест состоит из 4 частей:
- входные (тестовые) данные
- предусловие, т.е. некоторое состояние системы, при котором мы сможем выполнить необходимую проверку
- взаимодействие с web-приложением
- проверка — сравнение ожидаемого результата с полученным. В MS Unit Testing Framework для этого существует отдельный класс Assert
При этом важно обеспечить атомарность тестов — тест должен проверять одну логическую операцию и в идеале иметь одну единственную проверку. Плюсы данного подхода следующие:
- сокращение времени анализа результатов тестов
- не нужно тратить время на реализацию масштабного логирования (не стоит забывать, что MS Unit Testing Framework умеет собирать всевозможную диагностическую информацию в процессе выполнения теста, например: стэк вызовов, лог событий, IntelliTrace, запись фото и видео, анализ кодового покрытия)
Описание web-страниц тестируемого продукта
Что же будут представлять из себя описания страниц?
Во-первых, это описания элементов, с которыми мы будем работать, т.е. способ распознавания их по id, классу, имени, xpath и др. Не надо описывать сразу все имеющиеся на странице элементы, это нерациональная трата времени. При этом все эти описания должны быть приватными и не выходить за рамки класса страницы.
Во вторых, страница будет содержать свойства (getters) и методы, с помощью которых тесты смогут получить информацию со страницы, например значение какого-нибудь текстового поля.
И в третьих, страница будет содержать методы для совершения действий на самой странице, например клик по кнопке. Важно отметить, что описание страницы не должно содержать никакой логики и никаких проверок! Проверки должны быть в тестах. И в то же время, здесь не должно быть никаких вызовов Selenium WebDriver API.
Утилиты
В данном проекте, как минимум, будут находится обертки над Selenium WebDriver API. В последствии это место станет скоплением всевозможных helper'ов, утилит, расширений и т.д. до их вынесения в отдельные сущности и проекты.
Заключение и пример
Таким образом, нужно четко разграничить логику наших автотестов, для этого мы и создали три отдельных проекта. Я не исключаю, что в процессе развития проекта появятся и другие логические уровни со своими сущностями, но минимум будет такой.
Далее я покажу один простой пример и на этом закончу статью. Если она окажется интересной, я обязательно напишу продолжение, где опишу детали реализации тестов, страниц и оберток над WebDriver API.
[TestClass]
public class LogOnTests : TestsBase
{
[TestMethod]
public void LogOnWithEmptyLogin()
{
#region TestData
const string login = null;
const string password = "password";
const string error = "Empty login!";
#endregion
Browser.Open(...);
LogOnPage.LogOn(login, password);
Assert.AreEqual(error, LogOnPage.Error,
"Error expected.");
}
}
public static class LogOnPage
{
private static readonly WebElement LoginEdit = new WebElement().ById("Login");
private static readonly WebElement PasswordEdit = new WebElement().ById("Password");
private static readonly WebElement LogOnButton = new WebElement().ById("LogOn");
private static readonly WebElement LogOnValidationError = new WebElement().ById("LogOnValidation");
public static void LogOn(string login, string password)
{
LoginEdit.Text = login;
PasswordEdit.Text = password;
LogOnButton.Click();
}
public static string Error
{
get { return LogOnValidationError.Text; }
}
}
P.S. Вспомнилась старинная русская поговорка: кто рано встает, тот отлаживает тесты.