t.me/atinfo_chat Telegram группа по автоматизации тестирования

Factory Pattern - как реализовать ?

page-factory
framework
page-object
Теги: #<Tag:0x00007f9c4b4f1480> #<Tag:0x00007f9c4b4f1340> #<Tag:0x00007f9c4b4f1200>

(Taras) #1

почитал что есть возможность сделать так что б классы которые описывают реализации страниц отдельных взаимодействовали между собой, тоесть
tсли у нас есть один базовый клас Страница, от него 2 чайлда - Страница Логина, Страница Мейн например, тоже 2-е страници в отдельних классах, то можно реализовать Page Object таким образом чтоб еще и задействовать Factory Pattern что б Страница Логина, Страница Мейн могли “стучать” к друг другу. Page Factory Pattern говорят есть такая штука, может кто то обьяснить что это и как его едят, или я вообще не прав ?))


(Дмитрий Жарий) #2

Возьмем книжный пример:

http://code.google.com/p/selenium/wiki/PageFactory

Вот есть класс:

package org.openqa.selenium.example;

import org.openqa.selenium.WebElement;

public class GoogleSearchPage {
// Here’s the element
private WebElement q;

public void searchFor(String text) {
    // And here we use it. Note that it looks like we've
    // not properly instantiated it yet....
    q.sendKeys(text);
    q.submit();
}

}

И есть код который его использует:

package org.openqa.selenium.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.PageFactory;

public class UsingGoogleSearchPage {
public static void main(String[] args) {
// Create a new instance of a driver
WebDriver driver = new HtmlUnitDriver();

    // Navigate to the right place
    driver.get("http://www.google.com/");

    // Create a new instance of the search page class
    // and initialise any WebElement fields in it.
    GoogleSearchPage page = PageFactory.initElements(driver, GoogleSearchPage.class);

    // And now do the search.
    page.searchFor("Cheese");
}

}

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

GoogleSearchPage page = PageFactory.initElements(driver, GoogleSearchPage.class);

Как это работает: initElements:

  1. Создает новый экземпляр класса, переданного как второй параметр
  2. Магическим образом инициализирует его члены (private WebElement q;). В этом месте происходит очень много магии.
  3. Возвращает проинициализированный класс готовый к использованию.

Но, сам я этот механизм не использую.

Как вы можете заметить в соседнем топике (Почему Singleton антипаттерн), у меня есть страница GoogleSearchPage, которая в тесте создается обычным способом:

var googlePage = new GoogleSearchPage();

и сразу же готова для использования:

googlePage.Search(googleSearchPhrase);

В данном примере, элемент строки поиска Гугла "ленивый", и самостоятельно инициализируется когда его вызовут


(Taras) #3

Могу ли я реализовать доступ через наследование просто ?


(Taras) #4

тоесть
UsingGoogleSearchPage extends GoogleSearchPage {

}


(Дмитрий Жарий) #5

В таком случае, можете попробовать проинициализировать пейджу при помощи варианта:

PageFactory.initElements(driver, this);


(Taras) #6

у меня такая конструкция
есть клас Base - в нем вебдрайвер и разные перегруженные методы, парсеры, логеры подключены итд, создаються обьекты других класов, например робота, Сикули и Джава Скриптом разных которые можна юзать в тестах.
От него extend-аються класы страниц, что то типа Вашего GoogleSearchPage.

От GoogleSearchPage я екстендаю класы, что то типа вашего UsingGoogleSearchPage, где пишу тесты свои, потом их просто в отдельном класе Suit запускаю)

Так вот, я так понимаю можна сделать следующее, в класе Base создать екземляры всех страниц типа

Page1 page = PageFactory.initElements(driver, Page1.class); Page2 page = PageFactory.initElements(driver, Page2.class); .......... PageN page = PageFactory.initElements(driver, PageN.class);

PageI наследуеться от Base

и при этом каждый такой клас будет иметь доступ до проинстанциированого класа любого другого, либо же:

в каждом PageI создавать конструктор:

public PageI (){ PageFactory.initElements(getDriver(), this); }

потом в любом другом PageJ когда я создам екземляр PageI - он уже будет проинстанциированый

Так подойдет, или я не прав ?
Если нет то посоветуйте как мне переделать что б было правильно ?) Спасибо большое)


(Дмитрий Жарий) #7

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

Единственное, хочу уточнить, что в классе Base лучше инициализацию перенести в конструктор: public class Base { public Page1 page1;

public  Base()
{
	page1 = PageFactory.initElements(driver, Page1.class);
	// или page = new Page1(); // если initElements в конструкторе Page1
	// 
}

}


(Taras) #8

Ок, спасибо Вам !)