Простой и удобный шаблон тестового фреймворка на selenide для UI автотестов

    Здравствуйте.

    В этой статье я бы хотел поделиться своим опытом автоматизации функционального тестирования. Речь пойдет о написании удобного и надежного тестового фреймворка.

    Что будем использовать: 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
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 4

      0
      Как мне везет, что я натыкаюсь на нужные статьи, спасибо!
        0
        я правильно понял, что если у меня добавится еще страница, скажем UserPage, тесты не заработают, пока я не протащу эту страницу еще в PageBuilder, а потом еще в App?
          0
          нет, страницу можно использовать отдельно и создавать её в тестах. Но через App удобнее будет.
          0
          а если возвращать саму старницу тут:
          public NextPage login(String email, String password) {

          то можно писать цепочки:
          app.loginPage
            .open()
            .login()
            .tapSomeButton()
            .doSomething()

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

          Самое читаемое