Здравствуйте.
В этой статье я бы хотел поделиться своим опытом автоматизации функционального тестирования. Речь пойдет о написании удобного и надежного тестового фреймворка.
Что будем использовать: Java, Selenide, Alure, TestNG, Maven.
Проект на GitHub — SelenideBoilerplate.
Часто в статьях по автоматизации тестирования приводятся далекие от реальности примеры, например:
Есть много похожих примеров по ожиданиям, page object'ам и т.д. В итоге начинающему тестировщику может быть сложно правильно и удобно все организовать. Проект обрастает костылями из-за чего писать новые тесты и поддерживать старые становится все сложнее.
Также есть некоторые инструменты, которые на мой взгляд слишком многословны и переусложнены.
Я покажу простой, удобный и легко расширяемый тестовый фреймворк, работать с которым гораздо легче чем с обычным selenium и который я успешно использовал на нескольких проектах. Этот проект это основа, на реальных проектах все немного сложнее (паралеллизация, remoteDriver, много тестов и т.д.).
Начнем с модулей app и pages.
Обычно в примерах приводят довольно простые страницы, где все помещается в одном классе. Но на реальных проектах могут быть довольно большие страницы, описывать весь функционал которых в одном классе, не самая лучшая идея. Например это может быть страница пополнения счета с множеством форм разных платежных систем.
В этом случае лучше разбить страницу на несколько классов и даже элементов (например, товар в корзине) и собирать все это вместе в основном классе страницы.
Поэтому лучше создавать все страницы в одном месте, а именно в классе PageBuilder.
В классе AppConfig хранятся настройки тестируемого веб-приложения. Например — адрес сайта, тестовые пользователи и т.п. В этом проекте это просто адрес сайта.
Это главный класс в данном модуле. В конструкторе класса App создаются все страницы.
Благодаря такому подходу не нужно постоянно создавать page object'ы в тестах, создается только объект App из которого и достаются нужные страницы.
Также в классе App могут быть такие методы как — регистрация, оформление и создание заказа и т.п.
То есть большие операции в которых участвует несколько page object'ов и которые часто нужны в тестах.
Благодаря Selenide работать page object'ами очень просто. Все страницы наследуются от базового класса BasePage. В конструктор page object'а передается относительный url страницы.
Все элементы страницы имеют модификатор доступа public, благодаря чему можно писать тесты как в императивном так и в декларативном стилях. Также из элементов можно доставать необходимые данные, например текст или какой-то атрибут.
Локатор хранится только одном месте. Вся логика страницы должна быть описана в методах страницы.
При таком подходе, если что-то ломается или меняется, в большинстве случаев не нужно переписывать тесты, просто дорабатывается метод или локатор меняется на актуальный.
В модуле helpers хранятся 2 важных класса:
TestConfig — Из этого класса можно достать настройки с которыми запускаются тесты. Также здесь указаны настройки по умолчанию.
Тесты запускаются командой
Значения переменных достаются из командной строки и благодаря классу TestConfig становятся доступны в тестах и в приложении.
Можно например менять url приложения в зависимости от окружения (dev, stage, production).
Класс Driver это моя обертка над selenium и selenide драйверами с парой полезных методов.
Самое важные методы:
Driver.initDriver() — здесь инициализируется драйвер / браузер.
Все тестовые классы наследуются от класса A_BaseTest, в котором создается объект приложения App, логгер, softAssert, открывается и закрывается браузер, очищаются куки после каждого теста.
Также есть A_BaseTestListener в котором можно логировать ошибки.
Тесты выглядят примерно так. Легко читать, легко поддерживать.
Тестовые классы указываются в testng.xml.
В папке test-output хранятся логи и скриншоты — Driver.takeScreenshot().
Для отчетов используется Allure. После завершения тестов можно запустить команду
Проект на GitHub — SelenideBoilerplate
В этой статье я бы хотел поделиться своим опытом автоматизации функционального тестирования. Речь пойдет о написании удобного и надежного тестового фреймворка.
Что будем использовать: Java, Selenide, Alure, TestNG, Maven.
Введение
Проект на GitHub — SelenideBoilerplate.
Часто в статьях по автоматизации тестирования приводятся далекие от реальности примеры, например:
driver.get (“URL”)
driver.find_element_by_id(“ID”).send_keys(“username”)
driver.find_element_by_id (“ID”).send_keys(“password”)
driver.find_element_by_id(“submit”).click()
Есть много похожих примеров по ожиданиям, page object'ам и т.д. В итоге начинающему тестировщику может быть сложно правильно и удобно все организовать. Проект обрастает костылями из-за чего писать новые тесты и поддерживать старые становится все сложнее.
Также есть некоторые инструменты, которые на мой взгляд слишком многословны и переусложнены.
Я покажу простой, удобный и легко расширяемый тестовый фреймворк, работать с которым гораздо легче чем с обычным selenium и который я успешно использовал на нескольких проектах. Этот проект это основа, на реальных проектах все немного сложнее (паралеллизация, remoteDriver, много тестов и т.д.).
Инструменты
- Selenide — это библиотека для написания лаконичных и стабильных UI тестов с открытым исходным кодом. Selenide решает большую часть проблем с таймаутами, кликами на элементы которые не успели загрузиться и т.п. Также можно забыть про StaleElementReferenceException. Очень удобный и простой в освоении инструмент, поработав с которым уже не хочется возвращаться к selenium.
- WebDriverManager — Входит в Selenide. Библиотека которая берет на себя всю работу по скачиваю драйверов для браузера и установке путей к драйверам -
System.setProperty("webdriver.browser.driver", "/path_to_driver/driver");
- Allure для отчетов.
- TestNG — тестовый фреймворк.
- Maven — инструмент для автоматизации сборки проектов.
Структура проекта
Начнем с модулей app и pages.
Класс PageBuilder
Обычно в примерах приводят довольно простые страницы, где все помещается в одном классе. Но на реальных проектах могут быть довольно большие страницы, описывать весь функционал которых в одном классе, не самая лучшая идея. Например это может быть страница пополнения счета с множеством форм разных платежных систем.
В этом случае лучше разбить страницу на несколько классов и даже элементов (например, товар в корзине) и собирать все это вместе в основном классе страницы.
Поэтому лучше создавать все страницы в одном месте, а именно в классе PageBuilder.
package app;
import app.pages.LoginPage;
public class PageBuilder {
public static LoginPage buildLoginPage() {
return new LoginPage("/login");
}
public static BalancePage buildBalancePage() {
DepositForm depositForm = new DepositForm();
WithdrawalForm withdrawalForm = new WithdrawalForm();
return new BalancePage("/balance", depositForm, withdrawalForm);
}
}
Класс AppConfig
В классе AppConfig хранятся настройки тестируемого веб-приложения. Например — адрес сайта, тестовые пользователи и т.п. В этом проекте это просто адрес сайта.
package app;
public class AppConfig {
public static final String baseUrl = "https://google.com";
}
Класс App
Это главный класс в данном модуле. В конструкторе класса App создаются все страницы.
package app;
import app.pages.LoginPage;
public class App {
public LoginPage loginPage;
public App() {
loginPage = PageBuilder.buildLoginPage();
}
}
Благодаря такому подходу не нужно постоянно создавать page object'ы в тестах, создается только объект App из которого и достаются нужные страницы.
Также в классе App могут быть такие методы как — регистрация, оформление и создание заказа и т.п.
То есть большие операции в которых участвует несколько page object'ов и которые часто нужны в тестах.
Перейдем к page object'ам
Благодаря Selenide работать page object'ами очень просто. Все страницы наследуются от базового класса BasePage. В конструктор page object'а передается относительный url страницы.
Все элементы страницы имеют модификатор доступа public, благодаря чему можно писать тесты как в императивном так и в декларативном стилях. Также из элементов можно доставать необходимые данные, например текст или какой-то атрибут.
Локатор хранится только одном месте. Вся логика страницы должна быть описана в методах страницы.
При таком подходе, если что-то ломается или меняется, в большинстве случаев не нужно переписывать тесты, просто дорабатывается метод или локатор меняется на актуальный.
package app.pages;
import com.codeborne.selenide.SelenideElement;
import helpers.Driver;
import static com.codeborne.selenide.Selenide.*;
public class LoginPage extends BasePage {
public SelenideElement loginField = $("#login__username");
public SelenideElement passwordField = $("#login__password");
public SelenideElement signInButton = $("#login_enter");
public SelenideElement termsOfUseLabel = $("label[for=\"login_agree\"]");
public LoginPage(String pageUrl) {
super(pageUrl);
}
public void login(String email, String password) {
loginField.setValue(email);
passwordField.setValue(password);
termsOfUseLabel.click();
signInButton.click();
Driver.waitForUrlContains("account/accounts");
}
}
Остальное
В модуле helpers хранятся 2 важных класса:
TestConfig — Из этого класса можно достать настройки с которыми запускаются тесты. Также здесь указаны настройки по умолчанию.
Тесты запускаются командой
mvn test -Dbrowser=chrome -Dheadless=1
Значения переменных достаются из командной строки и благодаря классу TestConfig становятся доступны в тестах и в приложении.
Можно например менять url приложения в зависимости от окружения (dev, stage, production).
package helpers;
public class TestConfig {
public static String browser = "chrome";
public static String headless = "1";
public static void initConfig() {
browser = System.getProperty("browser") == null ? "chrome" : System.getProperty("browser");
headless = System.getProperty("headless") == null ? "1" : System.getProperty("headless");
}
public static boolean isHeadless() {
return headless.contains("1");
}
}
Класс Driver это моя обертка над selenium и selenide драйверами с парой полезных методов.
Самое важные методы:
Driver.initDriver() — здесь инициализируется драйвер / браузер.
public static void initDriver() {
// Get settings from command line
TestConfig.initConfig();
// Set settings for selenide browser
Configuration.pageLoadStrategy = "eager";
Configuration.browserSize = "1920x1080";
Configuration.holdBrowserOpen = false;
Configuration.screenshots = false;
if(TestConfig.isHeadless()) {
Configuration.headless = true;
} else {
Configuration.headless = false;
}
switch (TestConfig.browser) {
case "chrome":
Configuration.browser = Browsers.CHROME;
break;
case "firefox":
Configuration.browser = Browsers.FIREFOX;
break;
default:
Configuration.browser = Browsers.CHROME;
break;
}
}
Driver.clearCookies()
Driver.close()
Тесты
Все тестовые классы наследуются от класса A_BaseTest, в котором создается объект приложения App, логгер, softAssert, открывается и закрывается браузер, очищаются куки после каждого теста.
Также есть A_BaseTestListener в котором можно логировать ошибки.
Тесты выглядят примерно так. Легко читать, легко поддерживать.
import org.testng.annotations.Test;
public class ExampleTest extends A_BaseTest
{
@Test
public void loginViaEmail() {
app.loginPage.open();
app.loginPage.login("email@email.com", "passwords");
logger.info("Sample info message");
softAssert.assertEquals(2,2);
softAssert.assertAll();
}
}
Тестовые классы указываются в testng.xml.
В папке test-output хранятся логи и скриншоты — Driver.takeScreenshot().
Для отчетов используется Allure. После завершения тестов можно запустить команду
allure serve target/allure-results
и посмотреть отчет.Проект на GitHub — SelenideBoilerplate
DenBalDen
Как мне везет, что я натыкаюсь на нужные статьи, спасибо!