Я только начал использовать WebDriver, и я пытаюсь изучить лучшие практики, в частности, используя PageObjects и PageFactory.
Я понимаю, что PageObjects должны раскрывать различные операции на веб-странице и изолировать код WebDriver от тестового класса. Довольно часто одна и та же операция может привести к переходу на разные страницы в зависимости от используемых данных.
Например, в этом гипотетическом сценарии входа в систему, предоставляя учетные данные администратора, вы попадаете на страницу AdminWelcome и предоставляете учетные данные Клиента на странице CustomerWelcome.
Таким образом, самый простой способ реализовать это - выставить два метода, которые возвращают разные объекты PageObjects...
Вход в систему PageObject
package example;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class Login {
@FindBy(id = "username")
private WebElement username;
@FindBy(id = "password")
private WebElement password;
@FindBy(id = "submitButton")
private WebElement submitButton;
private WebDriver driver;
public Login(WebDriver driver){
this.driver = driver;
}
public AdminWelcome loginAsAdmin(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, AdminWelcome.class);
}
public CustomerWelcome loginAsCustomer(String user, String pw){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, CustomerWelcome.class);
}
}
И выполните следующие действия в тестовом классе:
Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome = loginPage.loginAsAdmin("admin", "admin");
или
Login loginPage = PageFactory.initElements(driver, Login.class);
CustomerWelcome customerWelcome = loginPage.loginAsCustomer("joe", "smith");
Альтернативный подход
Вместо дублирования кода я надеялся, что существует более чистый способ разоблачения одного метода login()
, который возвращает соответствующий объект PageObject.
Я думал о создании иерархии страниц (или их реализации интерфейса), чтобы я мог использовать это как возвращаемый тип, но он чувствует себя неуклюжим. Я придумал следующее:
public <T> T login(String user, String pw, Class<T> expectedPage){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, expectedPage);
}
Это означает, что вы можете сделать следующее в тестовом классе:
Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome =
loginPage.login("admin", "admin", AdminWelcome.class);
или
Login loginPage = PageFactory.initElements(driver, Login.class);
CustomerWelcome customerWelcome =
loginPage.login("joe", "smith", CustomerWelcome.class);
Это гибко: вы можете добавить страницу ExpiredPassword и вообще не менять метод login()
- просто добавьте еще один тест и перейдите в соответствующие истекшие учетные данные и страницу ExpiredPassword как ожидаемую страницу.
Конечно, вы могли бы легко оставить методы loginAsAdmin()
и loginAsCustomer()
и заменить их содержимое вызовом общего login()
(который затем будет закрыт). На новой странице (например, странице ExpiredPassword) потребуется другой метод (например, loginWithExpiredPassword()
).
Это имеет то преимущество, что имена методов фактически означают что-то (вы можете легко увидеть, что есть 3 возможных результата входа в систему), API PageObject API немного проще в использовании (нет "ожидаемой страницы" ) но код WebDriver все еще используется повторно.
Дальнейшие улучшения...
Если вы разоблачили единственный метод login()
, вы могли бы сделать более очевидным, какие страницы могут быть достигнуты при входе в систему, добавив интерфейс-маркер к этим страницам (это, вероятно, не обязательно, если вы выставляете метод для каждого сценария).
public interface LoginResult {}
public class AdminWelcome implements LoginResult {...}
public class CustomerWelcome implements LoginResult {...}
И обновите метод входа в систему:
public <T extends LoginResult> T login(String user, String pw,
Class<T> expectedPage){
username.sendKeys(user);
password.sendKeys(pw);
submitButton.click();
return PageFactory.initElements(driver, expectedPage);
}
Любой подход, похоже, работает хорошо, но я не уверен, как он масштабируется для более сложных сценариев. Я не видел таких примеров кода, как это, поэтому мне интересно, что делают все остальные, когда действия на странице могут приводить к различным результатам в зависимости от данных?
Или обычной практикой является просто дублировать код WebDriver и выставлять множество разных методов для каждой перестановки данных/PageObjects?