Блог вебразработчика
  • ГЛАВНАЯ
  • ПОДПИСКА

Selenium и Page Object паттерн

Авг31
2012
Написал Tatyana

        Page Object – это шаблон проектирования, который широко используется в автоматизированном тестировании и позволяет разделять логику выполнения тестов от их реализации. Page Object как бы моделирует страницы тестируемого приложения в качестве объектов в коде. В результате его использования у вас получатся отдельные классы, отвечающие за работу с HTML каждой конкретной веб-страницы. Такой подход значительно уменьшает объем повторяющегося кода, потому что одни и те же объекты страниц можно использовать в различных тестах. Основное преимущество Page Object заключается в том, что в случае изменения пользовательского интерфейса, можно выполнить исправление только в одном месте, а не исправлять каждый тест, в котором этот интерфейс используется.
Класс PageObject не обязательно должен представлять собой всю страницу. Он может быть частью страницы, которая часто используется на сайте (или даже на одной странице). Это может быть, например, пагинатор или меню. Основной принцип состоит в том, что есть только один класс в Вашем проекте, который знает о структуре HTML конкретной страницы или ее части.

Разделение логики и реализации
Существует большая разница между логикой тестирования (что проверить) и его реализацией (как проверить). Пример тестового сценария: «Пользователь вводит неверный логин или пароль, нажимает кнопку входа, получает сообщение об ошибке». Этот сценарий описывает логику теста, в то время как реализация содержит в себе такие действия как поиск полей ввода на странице, их заполнение, проверку полученной ошибки и т.д. И если, например, измениться способ вывода сообщения об ошибке, то это никак не повлияет на сценарий теста, все также нужно будет ввести неверные данные, нажать кнопку входа и проверить ошибку. Но это напрямую затронет реализацию теста — необходимо будет изменить метод получающий и обрабатывающий сообщение об ошибке. При разделении логики теста от его реализации автотесты становятся более гибкими и их, как правило, легче поддерживать.

Page Object в Selenium
Паттерн Page Object в Selenium реализован с помощью библиотеки PageFactory и класса страницы. Page Object представляет собой отдельный класс, содержащий локаторы элементов, методы для работы с ними и конструктор принимающий в качестве параметра объект WebDriver. Методы класса Page Object могут возвращать объекты других Page Object классов. С помощью этого можно воссоздать копию переходов и поведения веб-приложения. Например, метод успешной регистрации в классе RegistrationPage должен возвращать экземпляр HomePage, потому что после регистрации на сайте пользователя перенаправляет на домашнюю страницу. Одним из следствий такого подхода является то, что необходимо моделировать как успешные, так и неуспешные методы. Или, например, в случае если нажатие на элемент может открывать различные страницы в зависимости от условий, то также необходимо создавать разные методы для каждого необходимого случая:

public class RegistrationPage {

	private WebDriver driver;

	public RegistrationPage(WebDriver driver) {
		this.driver = driver;
	}

	public HomePage registerUserSuccess(User user) {
		// успешная регистрация и переход на домашнюю страницу
	}

	public RegistrationPage registerUserError(User user) {
		// регистрация пользователя с неверно заполненными полями
		// вывод ошибки, остаемся на той же странице
	}
}

Поиск элементов на странице можно осуществлять в методах используя driver.findElement, а можно объявить элементы в классе декларативно, используя аннотацию @FindBy.

import java.util.List;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class HomePage {

	private WebDriver driver;

	/**
	 * Имя пользователя
	 */
	@FindBy(id = "profilename")
	private WebElement userName;

	/**
	 * Выход 
	 */
	@FindBy(linkText = "Выход")
	private WebElement exit;

	/**
	 * Элементы меню
	 */
	@FindBy(className = "menu_item")
	private List<WebElement> menuItems;

	public HomePage(WebDriver driver) {
		PageFactory.initElements(driver, this);
		this.driver = driver;
	}
}

@FindBy в качестве параметров принимает те же механизмы поиска, что и методы класса By.
Аннотация @FindBy работает только с использованием PageFactory. Без вызова PageFactory.initElements(driver, this); при обращении к элементам Вы получите NullPointerException. PageFactory инициализирует элементы при помощи вызова поиска driver.findElement. Инициализация веб-элементов происходит на странице не вовремя вызова методаinitElements, PageFactory использует, так называемую, LAZY инициализацию. То есть, поиск элемента будет осуществляться только при обращении к нему в ходе выполнения теста. Если вы никогда не используете элемент в PageObject, то findElement для него никогда не будет вызван. Так объявленный в классе несуществующий на странице элемент вызовет исключение только при попытке его использовать.

PageFactory поддерживает инициализацию элементов по умолчанию. Это позволяет опускать аннотацию @FindBy, и в этом случае имя поля в классе выступает как ID или name элемента на HTML-странице. Сперва драйвер ищет элемент по соответствию id, и если элемент не найден, то затем по имени класса. Инициализация без @FindBy, естественно, не работает для List<WebElement>, поскольку не принято иметь несколько элементов с одинаковым ID или name на странице.

Каждый раз при обращении к элементу драйвер будет снова и снова осуществлять его поиск на странице. Для сложных AJAX-приложений это как раз то, что нужно. Но для ускорения выполнения существует возможность кешировать найденные элементы. Тогда поиск будет осуществляться только один раз при первом обращении к элементу.

	@FindBy(id = "profilename")
	@CacheLookup
	private WebElement userName;

Но делайте это только если вы уверены, что:

  • элемент всегда будет на странице;
  • элемент не будет меняться;
  • Вы не покидаете HTML страницу и возвращаетесь обратно (StaleElementReferenceException).

Пример класса Page Object:

import org.junit.Assert;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class RegistrationPage {

	private static String URL_MATCH = "registration";

	private WebDriver driver;

	/**
	 * Логин
	 */
	@FindBy(id = "userLogin")
	private WebElement login;

	/**
	 * Пароль
	 */
	@FindBy(id = "regPassword")
	private WebElement password;

	/**
	 * Пароль подтверждение
	 */
	@FindBy(id = "passwordConfirmation")
	private WebElement passwordConfirm;

	/**
	 * E-mail
	 */
	@FindBy(id = "UserEmail")
	private WebElement email;

	/**
	 * Кнопка зарегистрировать
	 */
	@FindBy(id = "submitRegistration")
	private WebElement bSubmitRegister;

	/**
	 * Сообщение об ошибке
	 */
	@FindBy(id = "error-message")
	private WebElement registerError;

	public RegistrationPage(WebDriver driver) {
		// проверить, что вы находитесь на верной странице
		if (!driver.getCurrentUrl().contains(URL_MATCH)) {
            		throw new IllegalStateException(
						"This is not the page you are expected"
						);
		}

		PageFactory.initElements(driver, this);
		this.driver = driver;
	}

	/**
	 * Регистраци пользователя
	 * @param user - {@link User}
	 */	
	private void registerUser(User user) {
		System.out.println(driver.getTitle());
		login.sendKeys(user.login);
		password.sendKeys(user.password);
		passwordConfirm.sendKeys(user.passwordConfirmation);
		email.sendKeys(user.email);

		bSubmitRegister.click();
	}

	/**
	 * Успешная регистрация пользователя
	 * @param user - {@link User}
	 * @return {@link HomePage}
	 */
	public HomePage registerUserSuccess(User user) {
		registerUser(user);
		return new HomePage(driver);
	}

	/**
	 * Неуспешная регистрация
	 * @param user - {@link User}
	 * @return {@link RegistrationPage}
	 */
	public RegistrationPage registerUserError(User user) {
		registerUser(user);
		return new RegistrationPage(driver);
	}

	/**
	 * Проверить сообщение об ошибке
	 * @param user - {@link User}
	 * @return {@link RegistrationPage}
	 */	
	public RegistrationPage checkErrorMessage(String errorMessage) {
		Assert.assertTrue("Error message should be present", 
						registerError.isDisplayed());
		Assert.assertTrue("Error message should contains " + errorMessage, 
						registerError.getText().contains(errorMessage));
		return this;
	}
}

Вызов методов страницы регистрации в тесте:

	@Test
	public void registerUserTest() {
		driver.get("http://HOST_NAME/registration");
		User user = User.createValidUser();
		user.email = "not_valid_email";

		RegistrationPage registrationPage =  new RegistrationPage(driver);
		registrationPage
			.registerUserError(user)
			.checkErrorMessage(errorMessage)
			;

		user = User.createValidUser();

		registrationPage
			.registerUserSuccess(user)
			// ...
			// вызов методов HomePage 
			;
	}
  • Нравится
  • Tweet

Опубликовано в Selenium - Помечено Page Object, PageFactory, Selenium WebDriver
Рассказать всем Twitter Facebook Delicious StumbleUpon E-Mail
← Selenium WebDriver запуск через proxy
Selenium PageFactory и FieldDecorator (часть 1) →

Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/u0420283/data/www/internetka.in.ua/wp-includes/class-wp-comment-query.php on line 405

11 комментариев

  1. Артем Язынин's Gravatar Артем Язынин
    09.02.2013 at 12:21 | Permalink

    Интересно было почитать. Помню писал свою реализацию Page Factory, когда библиотеки еще не было. Отличный был опыт. И за статью спасибо 🙂

  2. Marina's Gravatar Marina
    08.05.2013 at 15:14 | Permalink

    Спасибо большое!

  3. Vladislav's Gravatar Vladislav
    06.09.2013 at 06:03 | Permalink

    Татьяна жаль что вы ничего больше не пишите в своем блоге((( каждый раз возвращаюсь к прочтению статей, и узнаю для себя что-то новое, вы никогда не думали о том , чтобы книжку издать?

    • Tatyana's Gravatar Tatyana
      06.09.2013 at 13:17 | Permalink

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

      P.S. Про книгу никогда не думала))))

  4. Tema's Gravatar Tema
    04.01.2014 at 22:53 | Permalink

    Я пока только учусь, и мне уже не поможет, но для будущих поколений не могли бы вы прикрепить код проекта? А то для новичка путаници много..

    Но описано классно, спасибо.

  5. Антон's Gravatar Антон
    25.09.2014 at 17:52 | Permalink

    почему все элементы страницы всегда private?

    • Николай's Gravatar Николай
      12.12.2014 at 15:41 | Permalink

      Потому что должен соблюдаться принцип инкапсуляции. Доступ к полям класса должен предоставляться через интерфейс, а не напрямую. Приведенных методов должно быть достаточно для работы с данной страницей. Если же появляется новая логика, которая требует обращения к приватным полям — добавляйте новый паблик-метод, реализующий её и общайтесь с объектами через него.

    • Евгений's Gravatar Евгений
      23.12.2014 at 10:01 | Permalink

      это называется инкапсуляция

  6. fr's Gravatar fr
    09.10.2015 at 08:09 | Permalink

    спасибо, очень доступно.
    скажите, а почему основные методы описываются в классе PageObject? Это как-то ускоряет работу или как?
    я все абсолютно методы держу в хелпере. В хелпере же инициализирую нужную страницу. а в тесте обращаюсь только к методам из хелпера. А если у меня будут методы в классе PageObject, смогу ли я так просто к ним обращаться из теста?

  7. Егор's Gravatar Егор
    20.04.2016 at 10:54 | Permalink

    Подскажите, пожалуйста, а почему вы называете Page Object шаблоном проектирования? Идея определить классы для объектов, с которыми приходится иметь дело, лежит в основе ООП. Например, если бы я разрабатывал ПО для тестирования интерфейсов мобильных приложений, то скорее всего, определил бы Screen Object’ы, а если бы мариновал огурцы — Cucumber Object’ы 🙂

  8. Thinker's Gravatar Thinker
    28.03.2017 at 12:04 | Permalink

    Этот код не запускается. В registerUser(User user) передаются нулл всё время.
    Я что-то не так делаю?
    User с соответсвующими полями создан.

Свежие записи

  • WebDriver и SSL Untrusted certificate
  • Видеозапись выполнения тестов Selenium
  • Selenium WebDriver: basic авторизация
  • BrowserMob Proxy + Selenium: автоматизация сбора данных о производительности
  • Hibernate 4: UserType пользовательский тип данных (часть 2)

Поиск

Рубрики

  • Hibernate ORM
  • SEO
  • Разное
  • Тестирование
    • JUnit
    • Selenium
    • Thucydides

Метки

Actions AJAX Alert AutoIt ChromeDriver Exceptions ExpectedConditions FindElement FirefoxDriver Hibernate InternetExplorerDriver Java Javascript Jenkins JUnit4 Maven PageFactory Page Object RemoteWebDriver Select Selenium IDE Selenium Server Selenium WebDriver switchTo Thucydides WebDriverWait XPath Автоматизированное тестирование база данных заработок в сети сеть Интернет скорость продвижения сайта статейное продвижение услуги продвижения

Реклама


Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Блог вебразработчика
Функциональное тестирование и продвижение сайтов

Яндекс.Метрика