Перейти к содержимому

Тестирование веб-приложений 2.0
онлайн, начало 25 января
Тестирование REST API
онлайн, начало 28 января
SQL для тестировщиков
онлайн, начало 28 января
Техники локализации плавающих дефектов
онлайн, начало 28 января
Фотография

Page Object ver.2

Page Object

  • Авторизуйтесь для ответа в теме
Сообщений в теме: 2

#1 Isidor2811

Isidor2811

    Новый участник

  • Members
  • Pip
  • 21 сообщений
  • ФИО:Дацюк Олег

Отправлено 11 Июнь 2018 - 09:41

Всем еще раз привет! Вот тут http://software-test...-nasledovaniia/ я создавал тему касающейся правильности создания архитектуры Page Object. Мне указали на мои ошибки, и я начал гуглить и искать информацию по их устранению.

 

 

И так:

Архитектура классов тут: https://www.screenca...om/t/uUoP0S0wN7

 

Пока что реализовал вот как:

Создал класс BaseTest, в котором у меня реализована инициализация драйвера, также убрал SetProperty с явным указанием в нем пути к драйверу заменив его dependency WebDriverManager в pom файле. В итоге получился такой код:

public class BaseTest {

    protected WebDriver driver;

    @BeforeClass
    public void setUpDriver(){
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
    }

    @AfterClass
    public void tearDown(){
        driver.quit();
    }
}

От этого класса у меня будут наследоваться все тестовые классы.

 

Дальше создал класс BasePage, от которого будут наследоваться все пейджы. Так как пейджам нужен драйвер, то в данном классе (BasePage) я создал конструктор, в итоге каждый пейдж который будет создаваться, получит драйвер через super(driver).

Также я тут создал метод find, который заменит длинное написание driver.findElement().

Код ниже:

public class BasePage {

    protected WebDriver driver;

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

    public WebElement find(By locator){
        return driver.findElement(locator);
    }
}

Дальше класс самой страницы. Тут я оставил пару методов просто для наглядности, что бы не копипастить весь класс. В итоге создаем конструктор страницы, получаем драйвер, создаем переменные типа By с которыми будем работать, создаем маленькие методы (например заполнить поле, выбрать с селекта), потом создаем метод cardFill() который обьеденит эти методы.

public class NewOrgRegistrationPage extends BasePage{

    public NewOrgRegistrationPage(WebDriver driver) {
        super(driver);
    }

    String url = "http://192.168.1.111:8085/share/page/context/mine/sxg-external-registration";
    By orgRegistrationReasonDropBox = By.name("prop_uxp_orgnRegistrationReason");
    By fullOrgNameField = By.name("prop_uxp_orgnName");


    public NewOrgRegistrationPage selectOrgRegistrationReason(){
        Select selectOrg = new Select(find(orgRegistrationReasonDropBox));
        selectOrg.selectByIndex(1);
        return this;
    }
    public NewOrgRegistrationPage setFullOrgNameField(String orgName){
        find(fullOrgNameField).sendKeys(orgName);
        return this;
    }
    public NewOrgRegistrationPage visit(){
        driver.get(this.url);
        return this;
    }

    public void cardFill(){
        visit();
        selectOrgRegistrationReason();
        setFullOrgNameField("some name");
    }
}

И наконец то сам тест класс

public class CreatingNewOrgTest extends BaseTest{

    @Test
    public void cardFill(){
        NewOrgRegistrationPage page = new NewOrgRegistrationPage(driver);
        page.cardFill();
    }
}

Жду конструктивной критики особенно от пользователя Noksa, так как прошлый раз очень хорошие были замечания.

 

Но помимо критики у меня сразу есть вопросы. 

 

1. Мне кажется что в тестовых классах я не должен иметь возможности делать driver.findElement, driver.click и т.д. Тоесть на прямую обращаться к драйверу. Или я ошибаюсь?

 

2. В архитектуре классов у меня есть также класс SummaryAPI. В лекции что я смотрел, от этого класса неследовались классы BasePage и BaseTest - тоесть в них была реализация чего то общего для этих двух классов, например того же метода find:

 public WebElement find(By locator){
        return driver.findElement(locator);
 }

Я этого к сожелению понять не могу, зачем мне этод метод в тестовых классах? Если я могу его создать в BasePage, что я собстевнно и сделал, так как только в пейджах которые наследуються от этого класса я и буду его использовать. В чем смысл заносить его в SummaryAPI, потом наследовать в BaseTest и в тестовом методе иметь возможность делать find(By name("q")).

Я много где видел советы по созданию класса общего для BasePage и BaseTest. Но что там должно быть? Наведите пожалуйста примеры. Спасибо!


  • 0

#2 Little_CJIOH

Little_CJIOH

    Гуру

  • Members
  • PipPipPipPipPipPip
  • 1 276 сообщений
  • ФИО:Власкин Павел
  • Город:Санкт-Петербург


Отправлено 11 Июнь 2018 - 11:27

1. да, вы понимаете правильно


  • 0

#3 Noksa

Noksa

    Активный участник

  • Members
  • PipPip
  • 117 сообщений
  • ФИО:Александр

Отправлено 11 Июнь 2018 - 18:28

Скажу от себя.

 

 

 

создаем маленькие методы (например заполнить поле, выбрать с селекта)

 

Предположим, что у вас будет на странице 20 полей, которые нужно заполнить и 5 селектов, которые нужно выбрать.

 

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

 

Здесь можно пойти другим путём. Сделать один универсальный метод, например "fillField", который будет принимать в себя два аргумента: enum и string.

Где enum - это перечисление всех полей\селектов, которые есть на странице, а string - соответственно чем нужно заполнить\что нужно выбрать.

 

Ну а в теле метода уже через switch реализовать заполнение\селект конкретных полей\селектов.

 

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

 

Далее.

 

 

 

Жду конструктивной критики

 

Я сторонник PageFactory с кастомным локатором\декоратором, поэтому для меня поиск элементов через findElement и поля с типом By - это некрасиво и глаза разбегаются.

 

Могу привести пример, почему PageFactory лучше, на мой взгляд.

Вы можете придумать свои собственные атрибуты (аннотации), которые можете использовать у каких-то элементов.

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

 

При поиске через чистый findElement, у вас тут же будет выброшено исключение, если элемент не существует или исчез из DOM страницы.

Конечно же, вы всегда можете обернуть вызов findElement для достижения нужного результата - но это тоже на мой взгляд не оптимально.

 

А при использовании PageFactory и своей собственной аннотации, вы можете указать, что конкретный элемент нужно ждать 3 секунды. И если спустя эти 3 секунды он не появился - тогда будет выброшено исключение.

Либо вы можете добавить аннотацию, чтобы не выбрасывалось исключение, а просто писался варн в лог и тест шёл дальше - словом, всё что захотите.

 

Пример с C#:

[FindBy(Id = "date_from")]
[ElementTitle("Операции с")]
[TimeToSearch(3)]
private ADatePicker _dateFromPicker;

При обращении к этому элементу, будут предприняты попытки его поиска в течении 3 секунд. 

Или можно использовать не хардкодное значение, а ссылаться на какое-то проперти, и при его изменении оно соответственно изменится у всех затронутых элементов:

[FindBy(Id = "date_from")]
[ElementTitle("Операции с")]
[TimeToSearch(App.Properties.Timeouts.Small)]
private ADatePicker _dateFromPicker;

А так же задавать нужный polling time, да в общем-то что угодно. 

Я, например, реализовал атрибут (аннотацию) для указания родительского элемента:

[FindBy(Id = "date_from", ParentElement = dateBlockName)]
[ElementTitle("Операции с")]
private ADatePicker _dateFromPicker;

Чтобы избежать дублирования XPath.

 

 

Далее.

 

 

 

Создал класс BaseTest, в котором у меня реализована инициализация драйвера, также убрал SetProperty с явным указанием в нем пути к драйверу заменив его dependency WebDriverManager в pom файле. В итоге получился такой код:

 

Хардкод хромдрайвера и до сих пор есть необходимость всюду пропихивать экземпляр драйвера.

 

 

 

Мне кажется что в тестовых классах я не должен иметь возможности делать driver.findElement, driver.click и т.д. Тоесть на прямую обращаться к драйверу. Или я ошибаюсь?

 

И да и нет.

У вас, как ни крути, будет доступен драйвер в тестовом классе. У вас же тестовый класс наследуется от базового, в котором драйвер protected.

Просто не используйте драйвер в тестовых классах в таких целях.

 

 

 В архитектуре классов у меня есть также класс SummaryAPI. В лекции что я смотрел, от этого класса неследовались классы BasePage и BaseTest - тоесть в них была реализация чего то общего для этих двух классов, например того же метода find:

 

Могу сказать по себе. 

Мне пришлось форкнуть Allure под C# и реализовать в нём возможность создания\добавления шагов и аттачей в [setup] и [teardown] методах.

 

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

В итоге для всех тестовых классов у меня будет создаваться отчет.

public abstract class ABaseTestConfig : AllureReport
    {
      ...
    }

Но это что касается базового тестового класса.

 

Для чего нужно иметь общий базовый класс и для базового тестового класса и для BasePage - честно говоря никогда не думал об этом.

 

Могу лишь предположить, что какие-то общие данные текущего запуска тестов \ теста, но вроде все (?) тестовые фреймворки и так это хранят в доступных через статичные классы контекстах. 


  • 1


Программирование на С# для тестировщиков
онлайн
Автоматизатор мобильных приложений
онлайн
Selenium WebDriver: полное руководство
онлайн
Программирование на Python для тестировщиков
онлайн




Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных

Яндекс.Метрика
Реклама на портале