- PVSM.RU - https://www.pvsm.ru -
Приветствую всех, кому предыдущие статьи оказались полезными или были просто интересны. В прошлой части мы разобрались с Selenium WebDriver, и теперь, перед тем, как приступать к написанию тестов, мы должны описать страницы тестируемого приложения. В превью перечислю основные моменты
Часть 1: Введение [1]
Часть 2.1: Selenium API wrapper — Browser [2]
Часть 2.2: Selenium API wrapper — WebElement [3]
Часть 3: WebPages — описываем страницы [4]
Вполне логично начать с проектирования базового класса. Что же будет общего у наших страниц? Как минимум:
В добавок к этому, класс PageBase будет содержать общие для всех страниц методы, которые зависят от конкретного приложения. Например, если на всех страницах сайта может выскакивать кастомное всплывающее окно, то мы напишем метод ClosePopup(). Или, например, на всех страницах присутствует меню сайта. Тогда это меню можно описать в базовом классе. В примере я это опущу.
namespace Autotests.WebPages
{
public abstract class PageBase
{
public Uri Url
{
get
{
Browser.WaitAjax();
return GetUriByRelativePath(RelativePath);
}
}
public void Open()
{
Contract.Requires(Url != null);
Contract.Ensures(Browser.Url == Url, string.Format("{0} != {1}", Browser.Url, Url));
Browser.WaitAjax();
if (Browser.Url == Url) return;
Browser.Navigate(Url);
}
public Type PageName()
{
return GetType();
}
protected void Navigate(Uri url)
{
Contract.Requires(url != null);
Browser.Navigate(url);
}
protected static Uri GetUriByRelativePath(string relativePath)
{
Contract.Requires(!string.IsNullOrEmpty(relativePath));
return new Uri(string.Format("{0}{1}", SharedSettings.TestEnvironmentUrl, relativePath));
}
private string RelativePath
{
get
{
const string rootNamespaceName = "Autotests.WebPages.Root";
const string stringToDelete = "Page";
var fullName = GetType().FullName;
Contract.Assume(fullName != null);
return fullName.Replace(rootNamespaceName, "").Replace(".", "/").Replace(stringToDelete, "");
}
}
}
}
RelativePath получает относительный путь к web-странице, исходя из названия и расположения класса, который ее описывает. Удаление магического слова «Page» — это костыль на случай, когда название страницы сайта совпадает с зарезервированными или занятыми названиями. В таком случае к названию класса описания страницы просто приписывается слово «Page».
SharedSettings.TestEnvironmentUrl — адрес тестируемого сайта. Может храниться в константах или в настройках проекта.
Теперь, чтобы попасть на сайт, нам необходимо пройти авторизацию (кстати, все знают чем авторизация отличается от аутентификации?).
Опишем страницу LogOn:
public class LogOn : PageBase
{
#region Elements
private static readonly WebElement LoginEdit = new WebElement().ById("Login");
private static readonly WebElement PasswordEdit = new WebElement().ById("Password");
private static readonly WebElement RememberMeCheckbox = new WebElement().ById("Remember");
private static readonly WebElement ValidationSummary = new WebElement().ByClass("ValidationSummary");
#endregion
public void DoLogOn(UserLoginInfo userLoginInfo)
{
LoginEdit.Text = userLoginInfo.Login;
PasswordEdit.Text = userLoginInfo.Password;
RememberMeCheckbox.SetCheck(userLoginInfo.RememberMe);
Browser.ExecuteJavaScript("$('#LogOnForm').submit()");
if (Browser.Url == Main.Url) return;
if (ValidationSummary.Exists()) throw new LogOnValidationException();
throw new Exception("Unknown logon exception.");
}
}
Итак, на странице у нас есть два поля ввода (логин и пароль), чекбокс «Запомнить меня» и кнопка «Войти». Я умышленно не стал описывать эту кнопку, а нажимаю на нее через Browser.ExecuteJavaScript, чтобы показать и такой способ манипуляции с элементами.
Метод DoLogOn принимает некоторую структуру данных, заполняет и отправляет форму. Если после этого отобразилась главная страница Browser.Url == Main.Url, то метод успешно завершает свою работу. Если вход не удался, и показана ошибка ValidationSummary.Exists(), то метод выбрасывает исключение LogOnValidationException. Во всех остальных (непредусмотренных) случаях выбрасывается исключение с сообщением «Unknown logon exception.»
Класс LogOn унаследовал от PageBase некоторые методы и свойства, например метод Open(). Бывают ситуации, когда страницу необходимо открыть с какими-либо параметрами. Для этого придется написать в классе LogOn перегрузку для Open:
public void Open(int userId)
{
var url = new Uri(string.Format("{0}?userId={1}", Url, userId));
Navigate(url);
}
В этом методе мы формируем новый Url (добавляем id пользователя) и вызываем метод Navigate базового класса.
Заметьте, что нет никакой скрытой инициализации (вспомните PageFactory), элементы будут искаться в момент доступа к ним.
В принципе, можно и не использовать фасад. Мне так было удобно, поскольку классы страниц не статические, и необходимо создавать экземпляры. Для примера (см. картинку сверху), класс Pages будет выглядеть вот так:
namespace Autotests.WebPages
{
public static class Pages
{
public static LogOn LogOn = new LogOn();
public static class Home
{
public static Help Help = new Help ();
public static Main MainLogOut = new MainLogOut ();
}
}
}
Таким образом, из тестов мы сможем работать со страницами следующим образом:
Pages.LogOn.DoLogOn(...);
Pages.Home.Help.Open();
Это весьма удобно, иерархия страниц повторяет иерархию сайта.
Фуф, эта часть далась мне довольно легко, да и кода было немного. Как обычно, пишите любые вопросы/предложения в личку или в комментариях. В следующей части, наконец-то, будем писать автотесты =) В ней же я приведу ответы на самые частые вопросы и дам ссылку на рабочую версию фреймворка.
Автор: natexriver
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/testirovanie/35113
Ссылки в тексте:
[1] Часть 1: Введение: http://habrahabr.ru/post/178321/
[2] Часть 2.1: Selenium API wrapper — Browser: http://habrahabr.ru/post/180047/
[3] Часть 2.2: Selenium API wrapper — WebElement: http://habrahabr.ru/post/180357/
[4] Часть 3: WebPages — описываем страницы: http://habrahabr.ru/post/180705/
Нажмите здесь для печати.