Как писать автотесты на java selenium
Перейти к содержимому

Как писать автотесты на java selenium

  • автор:

Автотест на Java + Selenium. Подскажите по архитектуре Page Object и логике

Собственно, я не совсем понимаю как это всё связать и как прописать главную логику. Буду очень благодарен за развёрнутые ответы.

Отслеживать
задан 25 мая 2021 в 9:54
1 1 1 бронзовый знак

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

ответ не истина последней инстанции. просто в комментариях не поместился бы. я бы предложил другой вариант.

как только вы нашли список WebElement, то после манипуляций на странице элементы из списка могут быть не доступны. Тогда вы получите NoSuchElementException. Поэтому, лучше получить список из страницы скидки, страницу не трогать, открыть каждый элемент в новой вкладке, получить скидку, закрыть вкладку, открыть другой элемент в новой вкладке.

  1. открыть страницу main
  2. перейти в страницу скидки
  3. описать страницу скидки таким образом, чтобы List заполнялись все товары. (по умолчанию их 24) ( //*[@id=»products_on_sale_pagination_contents»]/div вот их пути )
  4. пройтись по списку for-ом + ограничить количество вашим динамическим значением.
  5. для каждого элемента открыть его в новой вкладке switchToTab
  6. инициализировать новый класс, который описывает страницу товара, где описано как достать цену, акцию и прочее, new Products(webdriver).WaitForLoad().GetMePricePlease()
  7. тут можно либо закрыть таб, либо просто перейти в первый таб. где список товаров
  8. сделать тоже самое для другого элемента

итого вы собрали список нужных цен.

плюсы подхода в том, не получите NoSuchElementException, помимо этого элементы останутся на своих местах и не будут перемещены, если один из них исчез из скидок или новый добавился.

минусы: ограничение 24 элемента. либо вам перед инициализацией нужно кликать на «показать еще 24», «показать еще 24», «показать еще 24»

Как писать автотесты с Selenium

Как писать автотесты с Selenium

Автоматизируем проверку имени пользователя на Java.

Selenium — это инструмент с открытым кодом для автоматизации тестирования WEB. С его помощью можно заменить рутинные операции, которые вынуждены делать мануальные тестировщики. Например, текстовый ввод или однотипные взаимодействия со множеством элементов страниц. Также Selenium облегчает тестирование разных локализаций, потому что взаимодействие с элементами страницы происходит на уровне кода.

Плюс Selenium в том, что он поддерживает самые популярные языки программирования (Java, Python, JavaScript, PHP).

статьи по теме:

Что нужно знать.

Чтобы лучше понять, как работает Selenium, напишем тест на Java.

Сравнение имени пользователя и логина: пишем код

Напишем тест, который будет открывать «Википедию», логиниться и проверять, соответствует ли имя пользователя его логину.

  • 1. Устанавливаем WebDriver— драйвер, который управляет работой браузера (открывает страницы и отправляет им команды). Тест будет написан для Chrome, поэтому понадобится драйвер для последней версии Chrome.
  • 2. Подтягиваем зависимость для Selenium-java в pom.xml Maven-проекта.
  org.seleniumhq.selenium selenium-java 4.0.0  
  • 3. Создаем три класса в папке Test:
    • WikiLoginPage (отвечает за работу со страницей авторизации).
    • WikiMainPage (отвечает за страницу, которая загружается после авторизации).
    • WikiLoginTest (основной тестовый класс).

    Также необходимо выставить небольшую задержку в 5 секунд, чтобы все статические элементы страницы успели загрузиться — timeouts().implicitlyWait(Duration.ofSeconds(5)). Аннотация @BeforeClass говорит о том, что этот метод будет вызван только один раз до запуска всех тестов. Метод quitDriver завершает работу драйвера и закрывает браузер.

    Аннотация @AfterClass обеспечивает его вызов только после того, как отработают все остальные методы. В переменные name и password прописываем данные пользователя, которые будем проверять.

    import org.junit.AfterClass; import org.junit.BeforeClass; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import java.time.Duration; public class WikiLoginTest < public static WebDriver driver; public static WikiLoginPage wikiLoginPage; public static WikiMainPage wikiMainPage; public static String url = "https://ru.wikipedia.org/w/index.php?title=Служебная:Вход&returnto=Заглавная+страница"; public static String name = "your_name"; public static String password = "your_password"; @BeforeClass public static void openWikiLoginPage() < System.setProperty("webdriver.chrome.driver", "c:/chromedriver.exe"); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5)); driver.get(url); wikiLoginPage = new WikiLoginPage(driver); wikiMainPage = new WikiMainPage(driver); >@AfterClass public static void quitDriver() < driver.quit(); >>
    • 5. Теперь нужен класс для работы со страницей ввода имени пользователя и пароля — WikiLoginPage. В нем с помощью PageFactory создаем хранилища объектов. К статическим объектам страницы (WebElement) обращаемся с помощью локаторов и аннотации @FindBy. В @FindBy передаем id элемента. Чтобы выбрать идентификатор для элемента, в Google DevTools нажимаем правой кнопкой мыши на элемент, а затем выбираем «посмотреть код» и копируем id.

    • В тесте мы будем использовать три локатора:
      • nameField — для имени пользователя;
      • passwordField — для пароля;
      • loginButton — для кнопки авторизации.
      import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class WikiLoginPage < public WebDriver driver; public WikiLoginPage(WebDriver driver) < PageFactory.initElements(driver, this); this.driver = driver; >@FindBy(id = "wpName1") WebElement nameField; @FindBy(id = "wpPassword1") WebElement passwordField; @FindBy(id = "wpLoginAttempt") WebElement loginButton; public void inputName(String name) < nameField.sendKeys(name); >public void inputPassword(String password) < passwordField.sendKeys(password); >public void clickLoginButton() < loginButton.click(); >>
      • 6. В классе WikiMainPage пишем локатор для определения имени пользователя (userName) и метод (getText) для получения текста из имени. У userName нет своего id, а потому в FindBy передаем xpath. xpath — это язык запросов, с помощью которого можно обращаться к элементам страницы.
      import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class WikiMainPage < public WebDriver driver; public WikiMainPage(WebDriver driver) < PageFactory.initElements(driver, this); this.driver = driver; >@FindBy(xpath = "//*[@id=\"pt-userpage\"]/a/span") private WebElement userName; public String getUserName()
      • 7. Когда оба класса готовы, дорабатываем WikiLoginTest — добавляем импорты для работы теста и пишем тестовый метод.
      import org.junit.Test; import org.junit.Assert;
      • Метод wikiLoginTest проверяет совпадение имени пользователя с отображаемым на странице. Для этого поочередно вызываются все методы, работающие с элементами страницы. После этого сравниваем значение текста элемента (wikiMainPage.getUserName()) с переменной, в которой хранится имя пользователя (name). Аннотация @Test помечает метод как тестовый.
      @Test public void wikiLoginTest()
      • 8. Запускаем тест — в левом нижнем углу отобразится тестовый класс (WikiLoginTest) с удачно запущенным тестовым методом (wikiLoginTest) и временем его работы. Если тесты падают, они становятся красными.

      • Этот автотест можно доработать. Например, вынести все переменные в отдельный конфигурационный файл. Также можно отойти от явного управления драйверами (особенно если будет использован не один браузер). Для этого понадобится библиотека WebDriverManager, которая автоматизирует загрузку драйверов, поиск браузеров в системе, запуск в Docker-контейнерах. С WebDriverManager не придется каждый раз открывать браузер при вызове тестовых методов.

      Готовый код можно найти тут.

      Архитектура высоких нагрузок

      Пишем автотесты эффективно — Subcutaneous tests

      Давайте представим себе гипотетическую ситауацию (в которой мы регулярно оказываемся). Вас назначили на проект «запилить» автоматизацию. Вам дают огромный тест план с большим количеством (тысячи их!) «ручных» тестов, и говорят что надо что-то сделать, и вотпрямщас. А еще, чтоб быстро и стабильно.

      Писать Unit тесты, или даже думать о TDD — уже поздно, код продукта давным-давно написан. Ваше слово, товарищ автотестер!

      image

      К счастью, есть небольшой трюк, который позволит и coverage повысить, и сделать тесты стабильными и быстрыми — Subcutaneous tests («подкожные тесты»), но обо всем по порядку.

      Суть проблемы

      Первый условный рефлекс автоматизатора — это взять Selenium (ну, или там, Selenide, или еще какую вундервафлю для UI тестов). Это такой стандарт индустрии, но есть много причин, почему «не взлетит»:

      • UI-тесты медленные. От этого никуда не деться. Их можно запускать параллельно, допиливать напильником и делать чуть-чуть быстрее, но они останутся медленными.
      • UI-тесты нестабильные. Отчасти потому, что они медленные. А еще потому, что Web-браузер и интерфейс пользователя не были созданы для того, чтобы ими управлял компьютер (в настоящее время данный тренд меняется, но не факт, что это хорошо).
      • UI-тесты — это наиболее сложные тесты в написании и поддержки. Они просто тестируют слишком много. (Это усиливается тем фактом, что, зачастую, люди берут «ручные» тест-кейсы и начинают их автоматизировать как есть, без учета разницы в ручном и автоматическом тестировании).
      • Нам говорят, что, якобы, UI-тесты эмулируют реального пользователя. Это не так. Пользователь не будет искать элемент на странице по ID или XPath локатору. Пользователь не заполняет форму со скоростью света, и не «упадет» если какой-то элемент страницы не будет доступен в какую-то конкретную миллисекунду. И даже теперь, когда браузеры разрабатываются с учетом того, что браузером можно программно управлять — это всего-лишь эмуляция, даже если очень хорошая.
      • Кто-то скажет, что некоторый функционал просто нельзя протестировать иначе. Я скажу, что если есть функционал, который можно протестировать только UI тестами (за исключением самой UI логики) — это может быть хорошим признаком архитектурных проблем в продукте.

      Альтернативное решение

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

      Исходный код приложения можно найти здесь: github.com/senpay/login-form. Вы были предупрежденны — в приложении куча багов и нет модных тулов и фреймворков.

      Если попробовать «накидать» чек лист для данного приложения, можно получить что-то вроде:

      Number Steps Expected results
      1 1. Enter a valid user name
      2. Click «Log in» button
      1.
      2. A new user is created.
      2 1. Enter an empty user name
      2. Click «Log in» button
      1.
      2. The error message is given.

      Выглядит просто? Просто! Можно ли написать UI-тесты? Можно. Пример написанных тестов (вместе с полноценным трехуровневым фреймворком) можно найти в LoginFormTest.java если перейти на uitests метку в git (git checkout uitests):

      public class LoginFormTest < SelenideMainPage sut = SelenideMainPage.INSTANCE; private static final String APPLICATION_URL = "http://localhost:4567/index"; @BeforeClass public static void setUpClass() < final String[] args = <>; Main.main(args); Configuration.browser = "firefox"; > @Before public void setUp() < open(APPLICATION_URL); >@After public void tearDown() < close(); >@Test public void shouldBeAbleToAddNewUser() < sut.setUserName("MyCoolNewUser"); sut.clickSubmit(); Assert.assertEquals("Status: user MyCoolNewUser was created", sut.getStatus()); Assert.assertTrue(sut.getUsers().contains("Name: MyCoolNewUser")); >@Test public void shouldNotBeAbleToAddEmptyUseName() < final int numberOfUsersBeforeTheTest = sut.getUsers().size(); sut.clickSubmit(); Assert.assertEquals("Status: Login cannot be empty", sut.getStatus()); Assert.assertEquals(numberOfUsersBeforeTheTest, sut.getUsers().size()); >> 

      Немного метрик для данного кода:
      Время выполнения: ~12 секунд (12 секунд 956 миллисекунд в последний раз, когда я запускал эти тесты)
      Покрытие кода
      Class: 100%
      Method: 93.8% (30/32)
      Line: 97.4% (75/77)

      Теперь давайте предположим, что Функциональные автотесты могут быть написаны на уровне «сразу под» UI. Эта техника и называется Subcutaneous tests («подкожные тесты» — тесты, которые тестируют сразу под уровнем логики отображения) и была предложена Мартином Фаулером достаточно давно [1].

      Когда люди думают о «не UI» автотестах, зачастую они думают сразу о REST/SOAP или иже с ним API. Но API (Application Programming Interface) — куда более широкое понятие, не обязательно затрагивающее HTTP и другие тяжеловесные протоколы.

      Если мы поковыряем код продукта, мы можем найти кое-что интересненькое:

      public class UserApplication < private static IUserRepository repository = new InMemoryUserRepository(); private static UserService service = new UserService(); < service.setUserRepository(repository); >public Map getUsersList() < return getUsersList("N/A"); >public Map addUser(final String username) < final String status = service.addUser(username); final Mapmodel = getUsersList(status); return model; > private Map getUsersList(String status) < final Mapmodel = new HashMap<>(); model.put("status", status); model.put("users", service.getUserInfoList()); return model; > > 

      Когда мы кликаем что-то на UI — вызывается один из этим методов, или добавляется новый объект User, или возвращается список уже созданных объектов User. Что, если мы используем эти методы напрямую? Ведь это самый настоящий API! И самое главное, что REST и иные API тоже работают по тому же принципу — вызывают некий метод «уровня контроллера».

      Используя напрямую эти методы, мы можем написать тест попроще да получше:

      public class UserApplicationTest < private UserApplication sut; @Before public void setUp() < sut = new UserApplication(); >@Test public void shouldBeAbleToAddNewUser() < final MapmyCoolNewUser = sut.addUser("MyCoolNewUser"); Assert.assertEquals("user MyCoolNewUser was created", myCoolNewUser.get("status")); Assert.assertTrue(((List) myCoolNewUser.get("users")).contains("Name: MyCoolNewUser")); > @Test public void shouldNotBeAbleToAddEmptyUseName() < final MapusersBeforeTest = sut.getUsersList(); final int numberOfUsersBeforeTheTest = ((List) usersBeforeTest.get("users")).size(); final Map myCoolNewUser = sut.addUser(""); Assert.assertEquals("Login cannot be empty", myCoolNewUser.get("status")); Assert.assertEquals(numberOfUsersBeforeTheTest, ((List) myCoolNewUser.get("users")).size()); > >

      Этот код доступен по метке subctests:

      git checkout subctests

      Попробуем собрать метрики?
      Time to execute: ~21 milliseconds
      Покрытие кода:
      Class: 77.8%
      Method: 78.1 (30/32)
      Line: 78.7 (75/77)

      Мы потеряли немного покрытия, но скорость тестов выросла в 600 раз.

      Насколько важна\существенна потеря покрытия в данном случае? Зависит от ситуации. Мы потеряли немного glue code, который может быть (а может и не быть) важным (рекомендую в качестве упражнения определить, какой код потерялся).

      • Добавить один UI-тест для проверки glue code, или
      • Если мы не ожидаем частых изменений glue code — оставить его без автотестов, или
      • Если у нас есть какой-то объем «ручного» тестирования — есть отличный шанс, что проблемы с glue code будут замечены тестировщиком, или
      • Придумать что-то еще (тот же Canary deployment)

      В итоге

      • Функциональные автотесты не обязательно писать на UI or REST/SOAP API уровне. Применение «Подкожных тестов» во многих ситуациях позволит протестировать тот же функционал с бОльшей скоростью и стабильностью
      • Один из минусов подхода — определенная потеря покрытия
      • Один из способов избежать потери покрытия — “Feature Tests Model”
      • Но даже при условии потери покрытия, прирост скорости и стабильности — значителен.

      Версия статьи на Английском языке доступна здесь.

      Если формат видео для вас больше подходит — можно посмотреть презентацию:

      Можно также подписаться на мой Youtube канал тут.

      Пишем автотест с использованием Selenium Webdriver, Java 8 и паттерна Page Object

      В этой статье рассматривается создание достаточного простого автотеста. Статья будет полезна начинающим автоматизаторам.

      Материал изложен максимально доступно, однако, будет значительно проще понять о чем здесь идет речь, если Вы будете иметь хотя бы минимальные представления о языке Java: классы, методы, etc.

      • установленная среда разработки Intellij IDEA (является самой популярной IDE, для большинства случаев достаточно бесплатной версии Community Edition);
      • установленные Java (jdk/openjdk) и Maven, прописанные в системные окружения ОС;
      • браузер Chrome и chromedriver — программа для передачи команд браузеру.

      Создание проекта

      Запустим Intellij IDEA, пройдем первые несколько пунктов, касающихся отправки статистики, импорта проектов, выбора цветовой схемы и т.д. — просто выберем параметры по умолчанию.

      В появившемся в конце окне выберем пункт «Create New Project», а в нем тип проекта Maven. Окно будет иметь вид:

      image

      • Maven — это инструмент сборки Java проектов;
      • Project SDK — версия Java, которая установлена на компьютере;
      • Create from archetype — это возможность создавать проект с определенным архетипом (на данном этапе данный чекбокс отмечать не нужно).

      Нажмем «Next». Откроется следующее окно:

      image

      Groupid и Artifactid — идентификаторы проекта в Maven. Существуют определенные правила заполнения этих пунктов:

      • Groupid — название организации или подразделения занимающихся разработкой проекта. В этом пункте действует тоже правило как и в именовании пакетов Java: доменное имя организации записанное задом наперед. Если у Вас нет своего доменного имени, то можно использовать свой э-мейл, например com.email.email;
      • Artifactid — название проекта;
      • Version — версия проекта.

      Нажмем «Finish»: IDE автоматически откроет файл pom.xml:

      image

      В нем уже появилась информация о проекте, внесенная на предыдущем шаге: Groupid, Artefiactid, Version. Pom.xml — это файл который описывает проект. Pom-файл хранит список всех библиотек (зависимостей), которые используются в проекте.

      Для этого автотеста необходимо добавить две библиотеки: Selenium Java и Junit. Перейдем на центральный репозиторий Maven mvnrepository.com, вобьем в строку поиска Selenium Java и зайдем в раздел библиотеки:

      image

      Выберем нужную версию (в примере будет использована версия 3.14.0). Откроется страница:

      image

      Копируем содержимое блока «Maven» и вставим в файл pom.xml в блок

      Таким образом библиотека будет включена в проект и ее можно будет использовать. Аналогично сделаем с библиотекой Junit (будем использовать версию 4.12).

      image

      Создание пакета и класса

      Раскроем структуру проекта. Директория src содержит в себе две директории: «main» и «test». Для тестов используется, соответственно, директория «test». Откроем директорию «test», кликом правой клавиши мыши по директории «java» выберем пункт «New», а затем пункт «Package». В открывшемся диалоговом окне необходимо ввести название пакета. Имя базового пакета должно носить тоже имя, что и Groupid — «org.example».

      Следующий шаг — создание класса Java, в котором пишется код автотеста. Кликом правой клавиши мыши по названию пакета выберем пункт «New», а затем пункт «Java Class».

      В открывшемся диалоговом окне необходимо ввести имя Java класса, например, LoginTest (название класса в Java всегда должно начинаться с большой буквы). В IDE откроется окно тестового класса:

      image

      Настройка IDE

      Прежде чем начать, необходимо настроить IDE. Кликом правой клавиши мыши по названию проекта выберем пункт «Open Module Settings». В открывшемся окне во вкладке «Sources» поле «Language level» по умолчанию имеет значение 5. Необходимо изменить значение поля на 8 (для использования всех возможностей, присутствующих в этой версии Java) и сохранить изменения:

      image

      Далее необходимо изменить версию компилятора Java: нажмем меню «File», а затем выберем пункт Settings.

      В открывшемся перейдем «Build, Execution, Deployment» -> «Compiler» -> «Java Compiler». По умолчанию установлена версия 1.5. Изменим версию на 8 и сохраним изменения:

      image

      Test Suite

      1. Пользователь открывает страницу аутентификации;
      2. Пользователь производит ввод валидных логина и пароля;
      3. Пользователь удостоверяется в успешной аутентификации — об этом свидетельствует имя пользователя в верхнем правом углу окна;
      4. Пользователь осуществляет выход из аккаунта путем нажатия на имя пользователя в верхнем правом углу окна с последующим нажатием на кнопку «Выйти…».

      Тест считается успешно пройденным в случае, когда пользователю удалось выполнить все вышеперечисленные пункты.

      Для примера будет использоваться аккаунт Яндекс (учетная запись заранее создана вручную).

      Первый метод

      В классе LoginTest будет описана логика теста. Создадим в этом классе метод «setup()», в котором будут описаны предварительные настройки. Итак, для запуска браузера необходимо создать объект драйвера:

      WebDriver driver = new ChromeDriver();

      Перед созданием объекта WebDriver следует установить зависимость, определяющую путь к chomedriver (в ОС семейства Windows дополнительно необходимо указывать расширение .exe):

      System.setProperty("webdriver.chrome.driver", "/usr/bin/chromedriver");

      Чтобы ход теста отображался в полностью открытом окне, необходимо сказать об этом драйверу:

      driver.manage().window().maximaze();

      Случается, что элементы на страницах доступны не сразу, и необходимо дождаться появления элемента. Для этого существуют ожидания. Они бывают двух видов: явные и неявные. В примере будет использовано неявное ожидание Implicitly Wait, которое задается вначале теста и будет работать при каждом вызове метода поиска элемента:

      driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

      Таким образом, если элемент не найден, то драйвер будет ждать его появления в течении заданного времени (10 секунд) и шагом в 500 мс. Как только элемент будет найден, драйвер продолжит работу, однако, в противном случае тест упадем по истечению времени.

      Для передачи драйверу адреса страницы используется команда:

      driver.get("https://passport.yandex.ru/auth")

      Выносим настройки

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

      Создадим в каталоге «test» еще один каталог с названием «resources», а в нем обычный файл «conf.properties», в который поместим переменную:

      loginpage = https://passport.yandex.ru/auth

      а также внесем сюда путь до драйвера

      chromedriver = /usr/bin/chromedriver

      image

      В пакете «org.example» создадим еще один класс «ConfProperties», который будет читать записанные в файл «conf.properties» значения:

      image

      package org.example; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; public class ConfProperties < protected static FileInputStream fileInputStream; protected static Properties PROPERTIES; static < try < //указание пути до файла с настройками fileInputStream = new FileInputStream("src/test/resources/conf.properties"); PROPERTIES = new Properties(); PROPERTIES.load(fileInputStream); >catch (IOException e) < e.printStackTrace(); //обработка возможного исключения (нет файла и т.п.) >finally < if (fileInputStream != null) try < fileInputStream.close(); >catch (IOException e) < e.printStackTrace(); >> > /** * метод для возврата строки со значением из файла с настройками */ public static String getProperty(String key) < return PROPERTIES.getProperty(key); >>

      Обзор первого метода

      image

      Метод «setup()» пометим аннотацией Junit «@BeforeClass», которая указывает на то, что метод будет выполняться один раз до выполнения всех тестов в классе. Тестовые методы в Junit помечаются аннотацией Test.

      package org.example; import org.junit.BeforeClass; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import java.util.concurrent.TimeUnit; public class LoginTest < /** * осуществление первоначальной настройки */ @BeforeClass public static void setup() < //определение пути до драйвера и его настройка System.setProperty("webdriver.chrome.driver", ConfProperties.getProperty("chromedriver")); //создание экземпляра драйвера WebDriver driver = new ChromeDriver(); //окно разворачивается на полный экран driver.manage().window().maximize(); //задержка на выполнение теста = 10 сек. driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //получение ссылки на страницу входа из файла настроек driver.get(ConfProperties.getProperty("loginpage")); >>

      Page Object

      При использовании Page Object элементы страниц, а также методы непосредственного взаимодействия с ними, выносятся в отдельный класс.

      Создадим в пакете «org.example» класс LoginPage, который будет содержать локацию элементов страницы логина и методы для взаимодействия с этими элементами.

      Откроем страницу авторизации в сервисах Яндекс (https://passport.yandex.ru/auth) в браузере Chrome. Для определения локаторов элементов страницы, с которыми будет взаимодействовать автотест, воспользуемся инструментами разработчика. Кликом правой кнопки мыши вызовем меню «Просмотреть код». В появившейся панели нажмем на значок курсора (левый верхний угол панели разработчика) и наведем курсор на интересующий нас элемент — поле ввода логина.

      В результате мы увидим этот элемент среди множества других. Теперь мы можем скопировать его локацию. Для этого кликаем правой кнопкой мыши по выделенному в панели разработчика элементу, выбираем меню «Copy» -> «Copy XPath».

      //*[@id="root"]/div/div/div[2]/div/div/div[3]/div[2]/div/div/div[1]/form/div[1]/div[1]/label

      Для локации элементов в Page Object используется аннотация @FindBy.

      Напишем следующий код:

      @FindBy(xpath = "//*[@id="root"]/div/div/div[2]/div/div/div[3]/div[2]/div/div/div[1]/form/div[1]/div[1]/label") private WebElement loginField;

      Таким образом мы нашли элемент на страницу и назвали его loginField (элемент доступен только внутри класса LoginPage, т.к. является приватным).

      Однако, такой длинный и страшный xpath использовать не рекомендуется (рекомендую к прочтению статью «Не так страшен xpath как его незнание». Если присмотреться, то можно увидеть, что поле ввода логина имеет уникальный id:

      image

      Воспользуемся этим и изменим поиск элемента по xpath:

      @FindBy(xpath = "//*[contains(@id, 'passp-field-login')]")

      Теперь вероятность того, что поле ввода пароля будет определено верно даже в случае изменения местоположения элемента на странице, возросла.

      Аналогично изучим следующие элементы и получим их локаторы.

      @FindBy(xpath = "//*[contains(text(), 'Войти')]") private WebElement loginBtn;

      Поле ввода пароля:

      @FindBy(xpath = "//*[contains(@id, 'passp-field-passwd')]") private WebElement passwdField;

      А теперь напишем методы для взаимодействия с элементами.

      Метод ввода логина:

      public void inputLogin(String login)

      Метод ввода пароля:

      public void inputPasswd(String passwd)

      Метод нажатия кнопки входа:

      public void clickLoginBtn()

      Для того, чтобы аннотация @FindBy заработала, необходимо использовать класс PageFactory. Для этого создадим конструктор и передадим ему в качестве параметра объект Webdriver:

      public WebDriver driver; public LoginPage(WebDriver driver)

      image

      package org.example; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class LoginPage < /** * конструктор класса, занимающийся инициализацией полей класса */ public WebDriver driver; public LoginPage(WebDriver driver) < PageFactory.initElements(driver, this); this.driver = driver; >/** * определение локатора поля ввода логина */ @FindBy(xpath = "//*[contains(@id, 'passp-field-login')]") private WebElement loginField; /** * определение локатора кнопки входа в аккаунт */ @FindBy(xpath = "//*[contains(text(), 'Войти')]/..") private WebElement loginBtn; /** * определение локатора поля ввода пароля */ @FindBy(xpath = "//*[contains(@id, 'passp-field-passwd')]") private WebElement passwdField; /** * метод для ввода логина */ public void inputLogin(String login) < loginField.sendKeys(login); >/** * метод для ввода пароля */ public void inputPasswd(String passwd) < passwdField.sendKeys(passwd); >/** * метод для осуществления нажатия кнопки входа в аккаунт */ public void clickLoginBtn() < loginBtn.click(); >>

      После авторизации мы попадаем на страницу пользователя. Т.к. это уже другая страница, в соответствии с идеологией Page Object нам понадобится отдельный класс для ее описания. Создадим класс ProfilePage, в котором определим локаторы для имени пользователя (как показателя успешного входа в учетную запись), а также кнопки выхода из аккаунта. Помимо этого, напишем методы, которые будут получать имя пользователя и нажимать на кнопку выхода.

      Итого, страница будет иметь следующий вид:

      image

      package org.example; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class ProfilePage < /** * конструктор класса, занимающийся инициализацией полей класса */ public WebDriver driver; public ProfilePage(WebDriver driver) < PageFactory.initElements(driver, this); this.driver = driver; >/** * определение локатора меню пользователя */ @FindBy(xpath = "//*[contains(@class, 'account__name_hasAccentLetter')]") private WebElement userMenu; /** * определение локатора кнопки выхода из аккаунта */ @FindBy(xpath = "//*[contains(@class, 'menu-item_action_exit menu__item menu__item_type_link')]") private WebElement logoutBtn; /** * метод для получения имени пользователя из меню пользователя */ public String getUserName() < String userName = userMenu.getText(); return userName; >/** * метод для нажатия кнопки меню пользователя */ public void entryMenu() < userMenu.click(); >/** * метод для нажатия кнопки выхода из аккаунта */ public void userLogout() < logoutBtn.click(); >>

      Интересный момент: в метод getUserName() пришлось добавить еще одно ожидание, т.к. страница «тяжелая» и загружалась довольно медленно. В итоге тест падал, потому что метод не мог получить имя пользователя. Метод getUserName() с ожиданием:

      public String getUserName() < WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(@class, 'account__name_hasAccentLetter')]"))); String userName = userMenu.getText(); return userName; >

      Вернемся к классу LoginTest и добавим в него созданные ранее классы-страницы путем объявления статических переменных с соответствующими именами:

      public static LoginPage loginPage; public static ProfilePage profilePage;

      Сюда же вынесем переменную для драйвера

      public static WebDriver driver;

      В аннотации @BeforeClass создаем экземпляры классов созданных ранее страниц и присвоим ссылки на них. Создание экземпляра происходит с помощью оператора new. В качестве параметра указываем созданный перед этим объект driver, который передается конструкторам класса, созданным ранее:

      loginPage = new LoginPage(driver); profilePage = new ProfilePage(driver);

      А создание экземпляра драйвера приведем к следующему виду (т.к. он объявлен в качестве переменной):

      driver = new ChromeDriver();

      Тест

      Теперь можно перейти непосредственно к написанию логики теста. Создадим метод loginTest() и пометим его соответствующей аннотацией:

      @Test public void loginTest() < //значение login/password берутся из файла настроек по аналогии с chromedriver //и loginpage //вводим логин loginPage.inputLogin(ConfProperties.getProperty("login")); //нажимаем кнопку входа loginPage.clickLoginBtn(); //вводим пароль loginPage.inputPasswd(ConfProperties.getProperty("password")); //нажимаем кнопку входа loginPage.clickLoginBtn(); //получаем отображаемый логин String user = profilePage.getUserName(); //и сравниваем его с логином из файла настроек Assert.assertEquals(ConfProperties.getProperty("login"), user); >

      Осталось лишь корректно все завершить. Создадим финальный метод и пометим его аннотацией @AfterClass (методы помеченные этой аннотацией выполняются один раз, после завершения всех тестовых методов класса).

      В этом методе осуществляется вход в меню пользователя и нажатие кнопки «Выйти», чтобы разлогиниться.

      @AfterClass public static void tearDown()

      Последняя строка нужна для закрытия окна браузера.

      Обзор теста

      package org.example; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import java.util.concurrent.TimeUnit; public class LoginTest < public static LoginPage loginPage; public static ProfilePage profilePage; public static WebDriver driver; /** * осуществление первоначальной настройки */ @BeforeClass public static void setup() < //определение пути до драйвера и его настройка System.setProperty("webdriver.chrome.driver", ConfProperties.getProperty("chromedriver")); //создание экземпляра драйвера driver = new ChromeDriver(); loginPage = new LoginPage(driver); profilePage = new ProfilePage(driver); //окно разворачивается на полный экран driver.manage().window().maximize(); //задержка на выполнение теста = 10 сек. driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //получение ссылки на страницу входа из файла настроек driver.get(ConfProperties.getProperty("loginpage")); >/** * тестовый метод для осуществления аутентификации */ @Test public void loginTest() < //получение доступа к методам класса LoginPage для взаимодействия с элементами страницы //значение login/password берутся из файла настроек по аналогии с chromedriver //и loginpage //вводим логин loginPage.inputLogin(ConfProperties.getProperty("login")); //нажимаем кнопку входа loginPage.clickLoginBtn(); //вводим пароль loginPage.inputPasswd(ConfProperties.getProperty("password")); //нажимаем кнопку входа loginPage.clickLoginBtn(); //получаем отображаемый логин String user = profilePage.getUserName(); //и сравниваем его с логином из файла настроек Assert.assertEquals(ConfProperties.getProperty("login"), user); >/** * осуществление выхода из аккаунта с последующим закрытием окна браузера */ @AfterClass public static void tearDown() < profilePage.entryMenu(); profilePage.userLogout(); driver.quit(); >>

      Запуск автотеста

      Для запуска автотестов в Intellij Idea имеется несколько способов:

      • Alt+Shift+F10;
      • Клик правой клавишей мышки по имени тестового класса, после чего в открывшемся меню выбрать Run;

      В результате выполнения автотеста, в консоли Idea я вижу, что тестовый метод loginTest() пройден успешно:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *