В мире много различных хороших практик в различных областях и сферах. Не является исключением и тестирование программного обеспечения. Сегодня мы с вами рассмотрим использование Page Object и Page Factory.
Я не буду сейчас рассказывать, что такое Page Object (паттерн/шаблон проектирования, который используется в автоматизированном тестировании) или Page Factory (класс из библиотеки Selenium), так как в интернете много информации о них. В данной статье я постараюсь на примерах показать, как с ними необходимо работать, чтобы вы взяли и начали сразу применять, то о чём мы сегодня будем говорить.
Для чего я стал использовать Page Object при написании автоматических тестов? Всё просто — есть элементы сайта, которые мной используются многократно в разных тестах. Если разработчик изменит элемент, а он используется мной в 100 тестах, то мне придётся править 100 мест в коде. При использовании Page Object мне достаточно исправить код в одном месте.
Рассмотрим на простом примере. Есть на странице результатов поиска Google логотип, ссылка которого имеет определённый id. Предположим, что каждый из 100 тестов я заканчиваю переходом на главную страницу кликая по логотипу сайта:
driver.FindElement(By.CssSelector("a#logo")).Click();
Если в определённый момент разработчики изменят id у логотипа, то все 100 тестов будут заканчиваться неудачей и мне надо будет править все 100 тестов. В этом случае нам на помощь приходит Page Object. Мы создадим класс, описывающий главную страницу сайта, а также класс описывающий страницу результатов поиска и в них будут перечислены все элементы страниц, к которым мы потом будем обращаться из всех 100 тестов. И когда разработчики изменят id у логотипа или ещё у какого-то из сотен элементов, то мы исправим его в одном месте, а сами тесты не будем трогать.
Рассмотрим сказанное выше на примере. Я не буду описывать как настроить Visual Studio для написания автоматических тестов на Selenium WebDriver об этом вы можете прочитать в соответствующей статье.
Итак, среда для тестов у нас подготовлена. CS-файл, в котором содержатся тесты я назвал «Test.cs». Теперь добавим в проект папку «pages», в которой у нас будут находиться страницы содержащие объекты страниц (объектами страниц будем называть элементы страниц: кнопки, ссылки и прочее.) В Solution Explorer правой кнопкой мыши на проекте и «Add -> New Folder»:
Теперь добавим в эту папку CS-файлы назвав их «PageHome.cs» (там будут объкты главной страницы) и «PageResultSearch.cs» (там будут объекты страницы результатов поиска):
Их рассмотрим позже, а сейчас рассмотрим обычный тест поиска в Google и возврата обратно на главную страницу:
[Test] public void Test_1() { driver.Navigate().GoToUrl("https://www.google.ru"); driver.FindElement(By.CssSelector("input[title='Поиск']")).Click(); // кликаем в поле ввода поисковой фразы driver.FindElement(By.CssSelector("input[title='Поиск']")).SendKeys("В чём сила брат?"); // вводим поисковую фразу driver.FindElement(By.CssSelector("input[value='Поиск в Google']")).Click(); // нажимаем на кнопку "Поиск в Google" Thread.Sleep(5000); // пауза за наблюдением результата поиска, для наглядности driver.FindElement(By.CssSelector("a#logo")).Click(); // возвращаемся на главную страницу кликнув по логотипу Thread.Sleep(5000); // пауза за наблюдением перехода на главную, для наглядности }
Знакомо и так вы писали до текущего момента. Теперь разберём написание теста с использованием Page Object. Для этого в созданные нами файлы описания объектов страниц добавим нужные нам объекты, с которыми в процессе тестов вы будем с вами работать.
PageHome.cs:
using OpenQA.Selenium; using OpenQA.Selenium.Support.PageObjects; namespace AutoTest.pages { class PageHome { /// <summary>Строка для ввода текста поиска</summary> [FindsBy(How = How.CssSelector, Using = "input[title='Поиск']")] public IWebElement TxtSearchForm { get; set; } /// <summary>Кнопка Поиск в Google</summary> [FindsBy(How = How.CssSelector, Using = "input[value='Поиск в Google']")] public IWebElement BtnSearchSubmit { get; set; } } }
PageResultSearch.cs:
using OpenQA.Selenium; using OpenQA.Selenium.Support.PageObjects; namespace AutoTest.pages { class PageResultSearch { /// <summary>Логотип-ссылка</summary> [FindsBy(How = How.CssSelector, Using = "a#logo")] public IWebElement LnkLogo { get; set; } } }
В этих файлах мы должны прописать все объекты, к которым мы будем обращаться в тестах. В нашем случае это будет поле поиска, кнопка поиска и логотип. В реальности тут будет намного больше информации, но для наглядности нам и этого достаточно.
Разберём «PageResultSearch.cs». В обычном тесте мы обращались к логотипу следующим образом:
driver.FindElement(By.CssSelector("a#logo"))
Т.е. находили его, а далее через точку указывали, что с ним делать.
В «PageResultSearch.cs» этот поиск элемента описан следующим образом:
[FindsBy(How = How.CssSelector, Using = "a#logo")] // искать элемент по селектору (How = How.CssSelector), который равен "a#logo" (Using = "a#logo")
Ну и конечно же задаётся его имя, по которому мы с ним будем работать:
public IWebElement LnkLogo { get; set; }
Сравните данные и вы поймёте принцип.
А как работать с элементами? Для этого напишем второй тест, который уже будет использовать при тестировании Page Object. Не забудьте в файле, где находятся сами тесты подключить «namespace» страниц «Page*.cs» в моём случае так:
using AutoTest.pages;
Сам тест:
[Test] public void Test_2() { driver.Navigate().GoToUrl("https://www.google.ru"); PageHome pageHome = new PageHome(); // чтобы могли обращаться к объектам из PageHome.cs PageFactory.InitElements(driver, pageHome); // инициализация элементов Page Object из PageHome.cs pageHome.TxtSearchForm.Click(); // кликаем в поле ввода поисковой фразы pageHome.TxtSearchForm.SendKeys("В чём сила брат?"); // вводим поисковую фразу pageHome.BtnSearchSubmit.Click(); // нажимаем на кнопку "Поиск в Google" Thread.Sleep(5000); // пауза за наблюдением результата поиска, для наглядности PageResultSearch pageResult = new PageResultSearch(); // чтобы могли обращаться к объектам из PageResultSearch.cs PageFactory.InitElements(driver, pageResult); // инициализация элементов Page Object из PageResultSearch.cs pageResult.LnkLogo.Click(); // возвращаемся на главную страницу кликнув по логотипу Thread.Sleep(5000); // пауза за наблюдением перехода на главную, для наглядности }
Запомните, что PageFactory инициализирует объекты/элементы страницы и обращается к ним, только когда в коде есть обращение к ним. Т.е. если в коде вы ни разу не обратились к какому-то объекту страницы, то его инициализация не производится хоть он и прописан в классе описания страницы. Эта важная особенность PageFactory. Можно работать без PageFactory, но тогда там происходит сразу инициализация всех объектов, находящихся в классе и если, инициализируя объект он не будет найден на открытой странице, то WebDriver выдаст исключение, что данный объект не найден на странице. Примеры без PageFactory я не разбираю, потому что работа без PageFactory доставляет массу неудобств.
Сравнив оба теста, вы увидите, что тест увеличился на 4 строки + появилось два файла, в которых также появился код. Если у вас десяток тестов и каждый уникален, то вам может не понадобится Page Object, однако если у вас сотни тестов и многие из них работают с одними и теми же элементами, то проектируйте тесты сразу используя Page Object, иначе после того как разработчики изменят несколько элементов вам придётся править не один десяток строк. В случае с Page Object достаточно будет поправить одну строку в классе описания объекта страницы. В нашем случае, если разработчики Google исправят id логотипа-ссылки на «logotwo», то мы поправим строку в «PageResultSearch.cs» на:
[FindsBy(How = How.CssSelector, Using = "a#logotwo")]
И не будет правиться сотня тестов, так как в них обращение к элементу идёт следующим образом:
pageResult.LnkLogo.Click();
Многие в классах описания страниц прописывают не только объекты страницы, с которыми надо будет работать, но и различные методы, чтобы в тестах было меньше кода, однако я сторонник того, чтобы в классах Page Object описывать объекты, а всю работу с ними описывать уже в самих тестах, тогда тесты становятся понятными и легко читаются.
Ещё рекомендую в классах описания страниц оставлять комментарии ко всем объектам, тогда при написании тестов вы в любой момент сможете прочесть, что за элемент в списке и облегчите себе и другим жизнь. Пример:
Надеюсь объяснил доступно. Далее вы можете экспериментировать как вам угодно. Прикладываю готовый проект с описанными выше примерами.
Спасибо большое за статью!
Все предельно просто и понятно!
спасибо бро!