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

Фотография

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 515 сообщений
  • ФИО:Власкин Павел
  • Город:Санкт-Петербург


Отправлено 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



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

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