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

Selenium WebDriver: полное руководство
онлайн, начало 19 октября
Логи как инструмент тестировщика
онлайн, начало 22 октября
Школа для начинающих тестировщиков
онлайн, начало 122 октября
Тестирование REST API
онлайн, начало 22 октября
Фотография

Как вынести создание объекта из теста

PageObject Selenium Java

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

#1 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 07 Декабрь 2017 - 12:45

Доброго времени суток!

Я недавно начал изучать автоматизированное тестирование с помощью selenium; пишу на Java. В качестве тестового фреймворка использую TestNG.

Также недавно познакомился с таким паттерном, как PageObject и на основе этого паттерна проектирую архитектуру автотестов. В данный момент имею следующую архитектуру: классы с тестами, которые наследуются от базового тестового класса (BaseTest); отдельно лежат классы с пэйджами, которые наследуются от базового пейджа (BasePage) и в самом вверху лежит абстрактный класс API, который наследуют два класса: BaseTest и BasePage. В этом классе API лежат хелперы и константы, которые я использую и в пейджах и в тестах. Вот в крации об архитектуре.

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

Пример: допустим есть тестовый класс LoginTests в котором лежит один тестовый метод loginWithInvalidEmail(). в этом тестовом методе я использую объект класса LoginPage. Я хочу это создание объекта вынести из метода в тестовый класс, вот как в в моем коде ниже: 

 

public class LoginTests extends BaseTest {

 

LoginPage loginPage = new LoginPage(driver);

@Test
public void loginWithInvalidEmail() {
open(TESTPROLINE);
loginPage.emailInput.sendKeys(invalidEmail);
loginPage.passwordInput.sendKeys(PASSWORD);
loginPage.submitButton.click();
assertThat(textToBePresentInElement((loginPage.errorMessage), "Email or password is incorrect!"));
}

 

Но проблема в том, что когда я запускаю этот тест, то происходит следующее: открывается браузер, он настраивается(размер на полный экран, задаются неявные ожидания) и после этого загружается моя страница TESTPROLINE и когда дело доходит до строчки "loginPage.emailInput.sendKeys(invalidEmail);", то тест падает с ошибкой java.lang.NullPointerException. я так понимаю тут проблема в базовом тестовом классе, в котором происходит та самая "настройка браузера", поэтому привожу также код из класса BaseTest:

public class BaseTest extends API {

public static WebDriver driver ;

@BeforeMethod
public void initializeDriver() {
System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\chromedriver_win32\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();
}

@AfterMethod
public void tearDown() {
// Close all browser windows and safely end the session
driver.quit();
}

}

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


  • 0

#2 BabyRoot

BabyRoot

    Специалист

  • Members
  • PipPipPipPipPip
  • 562 сообщений


Отправлено 07 Декабрь 2017 - 12:49

А покажите свой ЛогинПэйдж.


  • 0

#3 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 07 Декабрь 2017 - 12:53

/


  • 0

#4 Lzk

Lzk

    Специалист

  • Members
  • PipPipPipPipPip
  • 504 сообщений
  • ФИО:Олег
  • Город:Мск

Отправлено 07 Декабрь 2017 - 12:55

Инициализацию обьекта можно вынести в Before.

А чем тебя не устраивает создание обьекта страницы в тесте ? 

Я бы спрятал инит драйвером бы вот как раз.


  • 0

#5 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 07 Декабрь 2017 - 12:56

А покажите свой ЛогинПэйдж.

public class LoginPage extends BasePage {

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

@FindBy(id "inputEmail3")
public WebElement emailInput;

@FindBy(id "inputPassword3")
public WebElement passwordInput;

@FindBy(id "login_btn")
public WebElement submitButton;

}


  • 0

#6 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 07 Декабрь 2017 - 13:00

Инициализацию обьекта можно вынести в Before.

А чем тебя не устраивает создание обьекта страницы в тесте ? 

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


  • 0

#7 BabyRoot

BabyRoot

    Специалист

  • Members
  • PipPipPipPipPip
  • 562 сообщений


Отправлено 07 Декабрь 2017 - 13:13

Такую страницу надо инициализировать через пейджФактори.

https://github.com/S...iki/PageFactory

так не правильно:

LoginPage loginPage = new LoginPage(driver);


  • 0

#8 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 07 Декабрь 2017 - 13:23

Такую страницу надо инициализировать через пейджФактори.

https://github.com/S...iki/PageFactory

так не правильно:

LoginPage loginPage = new LoginPage(driver);

я инициализирую пейджФактори в конструкторе базового пейджа. То есть инициализирую страницу в тесте, а в конструкторе странице лежит ссылка на родительский конструктор : 

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

а вот и инициализация страницы в родительском классе: 

 

public class BasePage extends API {

private WebDriver driver;

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

}

 

Тоесть если я создание объекта засуну в тестовый метод. То все будет работать.


  • 0

#9 TatyanaV

TatyanaV

    Опытный участник

  • Members
  • PipPipPipPip
  • 315 сообщений
  • ФИО:Воробьева Татьяна


Отправлено 08 Декабрь 2017 - 11:28

Я предполагаю, что в тот момент, когда у вас инициализируется страница - driver == null.

 

ну на самом деле у меня в классе LoginTests не один тест, а несколько.

 

Если не планируете реализовывать PageManager - делаете в классе LoginTests метод:

private LoginPage loginPage() {
    if (loginPage == null) {
        loginPage = new LoginPage(driver);
    }
}

В методах-тестах используете уже не элемент loginPage, а метод loginPage().

Если элемент уже будет создан - все ок, будет использован он. Если его вдруг ещё не будет - он будет создан и инициализирован.

 

Но у Вас есть другая проблема.

Вы (в данный момент) инициализируете страницу при создании класса с тестами. Один раз.

А вот драйвер у Вас пересоздается заново перед каждым методом (стоит аннотация BeforeMethod, а не BeforeClass). Т.е. теоретически - и при Вашем текущем варианте, и при использовании предложенного выше метода - объект страницы уже на втором тесте будет ссылаться на несуществующий driver. В данном случае я имею ввиду, что из-за BeforeMethod "предыдущий" браузер будет закрыт после предыдущего теста, а для этого теста - будет открыт уже новый браузер, о котором объект страницы и знать не знает (он продолжает ссылаться на "старый" driver).

 

Тут два варианта:

1. все ваши тесты в этом классе НЕ требуют запуска нового браузера (м.б. нужен просто переход на "главную" страницу). Тогда лучше изменить аннотацию - браузер будет инициализироваться один раз перед запуском первого теста этого класса. Главное не забыть тогда и у tearDown аннотацию сменить.

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

 

Вообще - мне кажется более оптимальным вариантом использование PageManager.

Драйвер создается один раз (BeforeClass) и передается в конструктор PageManager.

PageManager рулит страницами, создаёт их, когда нужно - инициализирует имеющимся у него драйвером.

Тесты ничего не создают и не инициализируют - только используют страницы, запрошенные у PageManager (как он их создаёт / инициализирует и т.д. - сами тесты волновать не должно, т.к. это не их задача).


  • 0

#10 sanchos0210

sanchos0210

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

  • Members
  • Pip
  • 6 сообщений

Отправлено 12 Декабрь 2017 - 10:34

Я предполагаю, что в тот момент, когда у вас инициализируется страница - driver == null.

 

ну на самом деле у меня в классе LoginTests не один тест, а несколько.

 

Если не планируете реализовывать PageManager - делаете в классе LoginTests метод:

private LoginPage loginPage() {
    if (loginPage == null) {
        loginPage = new LoginPage(driver);
    }
}

В методах-тестах используете уже не элемент loginPage, а метод loginPage().

Если элемент уже будет создан - все ок, будет использован он. Если его вдруг ещё не будет - он будет создан и инициализирован.

 

Но у Вас есть другая проблема.

Вы (в данный момент) инициализируете страницу при создании класса с тестами. Один раз.

А вот драйвер у Вас пересоздается заново перед каждым методом (стоит аннотация BeforeMethod, а не BeforeClass). Т.е. теоретически - и при Вашем текущем варианте, и при использовании предложенного выше метода - объект страницы уже на втором тесте будет ссылаться на несуществующий driver. В данном случае я имею ввиду, что из-за BeforeMethod "предыдущий" браузер будет закрыт после предыдущего теста, а для этого теста - будет открыт уже новый браузер, о котором объект страницы и знать не знает (он продолжает ссылаться на "старый" driver).

 

Тут два варианта:

1. все ваши тесты в этом классе НЕ требуют запуска нового браузера (м.б. нужен просто переход на "главную" страницу). Тогда лучше изменить аннотацию - браузер будет инициализироваться один раз перед запуском первого теста этого класса. Главное не забыть тогда и у tearDown аннотацию сменить.

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

 

Вообще - мне кажется более оптимальным вариантом использование PageManager.

Драйвер создается один раз (BeforeClass) и передается в конструктор PageManager.

PageManager рулит страницами, создаёт их, когда нужно - инициализирует имеющимся у него драйвером.

Тесты ничего не создают и не инициализируют - только используют страницы, запрошенные у PageManager (как он их создаёт / инициализирует и т.д. - сами тесты волновать не должно, т.к. это не их задача).

Спасибо большое за совет с PageManager. Раньше про такое не слышал и поэтому чуть позже обязательно попробую. Сейчас решил проблему следующим образом:

Мои методы создания и закрытия драйвера с аннотациями @BeforeMethod и @AfterMethod находятся в родительском классе BaseTest (как я и писал в самом начале). А в классах с тестами я создал дополнительно метод также с аннотацией @BeforeMethod и запихнул туда инициализацию объектов, которые встречаются в тестах данного тестового класса и получается следующая картина: я запускаю тест, сначала отрабатывает метод из родительского класса, в которых создает драйвер, потом отрабатывает метод непосредственно из тестового класса, который создает нужные мне объекты, а потом уже отрабатывает сам тест, после чего метод из родительского класса закрывает браузер. Вот собственно и всё решение. 


  • 0


Selenium 2.0: стартовый уровень
онлайн, начало 9 ноября
Программирование на Java для тестировщиков
онлайн, начало 12 октября
Автоматизация функционального тестирования
онлайн, начало 5 октября
Selenium WebDriver: полное руководство
онлайн, начало 19 октября




Темы с аналогичным тегами PageObject, Selenium, Java

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

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

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