Компонентные объекты вместо объектов страницы в селене

Одним из самых популярных паттернов в тестировании на основе селена является объект страницы. К сожалению, нам часто приходится дублировать код, если мы используем его как есть. Рассмотрим следующую ситуацию:

  • Мы используем структуру пользовательского интерфейса с общим компонентом, скажем, какой-нибудь причудливой таблицей.
  • Таблица довольно сложная, есть фильтрация, сортировка, поиск
  • Таблица используется на нескольких страницах в приложении

Существует ли какая-либо существующая инфраструктура для создания более детализированных объектов компонентов вместо объектов страниц либо в селене, либо в сторонней библиотеке? Я имею в виду аннотации и связанную с ними инфраструктуру?


person Konstantin Solomatov    schedule 10.11.2016    source источник


Ответы (2)


Appium, который является мобильной реализацией selenium webdriver, имеет концепцию виджетов, которая является расширением объектов страницы. Существует класс Widget, который позволяет выполнять поиск относительно элемента, в том числе в веб-браузере. Вы можете проверить это в разделе тестирования исходного кода appium. Посмотрите в пакете io.appium.java_client.pagefactory_tests.widgets. Это поддерживает аннотацию FindBy и конструкцию WebElement, а также инициализацию PageFactory.

Поэтому вместо использования

@FindBy(.......)
private WebElement myTable;

вы можете использовать

@FindBy(container of the table....)
private Table myTable;

Класс таблицы теперь может иметь все соответствующие переменные и методы.

Часть POM.xml

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-api</artifactId>
    <version>2.53.1</version>
</dependency>
<dependency>
    <groupId>io.appium</groupId>
    <artifactId>java-client</artifactId>
    <version>4.1.2</version>
</dependency>

Тестовый класс --

import io.appium.java_client.pagefactory.AppiumFieldDecorator;

import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.PageFactory;

public class WidgetBrowTest {

    @Test
    public void test() {
        System.setProperty("webdriver.chrome.driver", "E:/Software Testing/Selenium/Jars/chromedriver.exe");

        WebDriver driver = new ChromeDriver();

        driver.get("http://stackoverflow.com/");


        SOHome soHome = new SOHome(driver);
        PageFactory.initElements(new AppiumFieldDecorator(driver), soHome);

        //Below two are from widget - First question in stackoverflow homepage
        System.out.println(soHome.getFirstQues().getQuesTitle());
        System.out.println(soHome.getFirstQues().getQuesTags());

        //Below two are from home page
        System.out.println(soHome.getLogoText());
        System.out.println(soHome.getMenuText());
    }
}

StackOverflow Главная -

import java.util.List;
import java.util.stream.Collectors;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class SOHome {

    @FindBy(css="div[id='hlogo'] > a")
    private WebElement logo;

    @FindBy(xpath="//div[@id='hmenus']//li/a")
    private List<WebElement> menuOpt;

    @FindBy(css="div[class='summary']")
    private SOQuesWidget firstQues;

    private WebDriver driver;


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

    public String getLogoText() {
        return logo.getText();
    }

    public List<String> getMenuText() {
        return menuOpt.stream().map(t -> t.getText()).collect(Collectors.toList());
    }

    public SOQuesWidget getFirstQues() {
        return firstQues;
    }
}

Виджет вопроса - первый вопрос

import java.util.List;
import java.util.stream.Collectors;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import io.appium.java_client.pagefactory.Widget;

public class SOQuesWidget extends Widget {

    @FindBy(css="a[class='question-hyperlink']")
    private WebElement quesTitle;

    @FindBy(xpath=".//div[starts-with(@class,'tags')]/a")
    private List<WebElement> quesTags;

    protected SOQuesWidget(WebElement element) {
        super(element);
    }

    public String getQuesTitle() {
        return quesTitle.getText();
    }

    public List<String> getQuesTags() {
        return quesTags.stream().map(t -> t.getText()).collect(Collectors.toList());
    }
}
person Grasshopper    schedule 11.11.2016
comment
Насколько я вижу, это работает только на мобильных устройствах. Есть ли такой инструмент для рабочего стола? - person Konstantin Solomatov; 12.11.2016
comment
Ознакомьтесь с фрагментами кода, добавленными для домашней страницы переполнения стека с помощью виджета, инкапсулирующего функциональность первого вопроса... - person Grasshopper; 12.11.2016
comment
Большое спасибо. Это то, что я хотел. - person Konstantin Solomatov; 12.11.2016
comment
Потерял некоторое время, думая, что мы должны использовать AppiumFieldDecorator на PageFactory.initElements, что является хитростью здесь вместе с виджетом. Спасибо за ваш ответ! - person Luís Silva; 10.04.2019

Объекты страницы - это неправильное название. Они не обязательно должны быть полностью заполненными страницами, чтобы следовать объектной модели страницы. Я бы создал класс таблицы (объект страницы), который содержит все локаторы и методы для объекта таблицы, а затем включил бы его в объекты страниц/страниц, где он появляется.

Например, если домашняя страница содержит табличный объект, то класс HomePage будет ссылаться на класс Table.

person JeffC    schedule 10.11.2016
comment
Когда я инициализирую страницу, все селекторы относятся к корневому документу. Я хотел бы, чтобы они применялись относительно некоторого элемента, чтобы я мог анализировать таблицу. - person Konstantin Solomatov; 11.11.2016
comment
Нет ли способа однозначно идентифицировать таблицу внутри таблицы, например. у таблицы есть идентификатор или какой-то другой способ идентифицировать тег TABLE? Я не думаю, что вы можете дать мне ссылку на образец страницы или хотя бы опубликовать соответствующий HTML-код для таблицы? Может быть, я могу помочь найти способ. - person JeffC; 11.11.2016
comment
Эта таблица является гипотетическим примером, иллюстрирующим ситуацию, когда мне нужно больше повторного использования кода. По сути, у меня есть элемент, и я хотел бы, чтобы он работал таким образом, чтобы я мог использовать аннотации FindBy относительно него или делать это каким-либо другим способом. - person Konstantin Solomatov; 11.11.2016
comment
Я использую именно этот метод на сайтах, для которых пишу автоматизацию, например. заголовок, нижний колонтитул, верхняя навигация, другие ссылки, такие как вход / выход, ссылки на корзину и так далее. Этот метод отлично работает. Если у вас есть конкретный случай, когда это не работает, напишите об этом в своем вопросе, и я посмотрю. - person JeffC; 11.11.2016
comment
Представьте, что у вас есть две таблицы на одной странице. Как выбрать тот или иной? - person Konstantin Solomatov; 12.11.2016
comment
Это зависит от HTML каждой из таблиц... имеют ли они уникальные атрибуты, например. идентификатор или класс или ??? - person JeffC; 12.11.2016
comment
@JefC Это сработает, но мне это не кажется хорошим решением. - person Konstantin Solomatov; 12.11.2016