如何实现可以返回不同页面对象的 WebDriver 页面对象方法
我刚刚开始使用WebDriver,我正在尝试学习最佳实践,特别是使用PageObjects和PageFactory。
我的理解是,PageObjects应该公开网页上的各种操作,并将WebDriver代码与测试类隔离开来。通常,相同的操作可能会导致根据使用的数据导航到不同的页面。
例如,在此假设的登录方案中,提供管理员凭据会将您带到“管理员欢迎”页面,而提供客户凭据会将您带到“客户欢迎”页面。
因此,实现这一点的最简单方法是公开两个返回不同页面对象的方法...
登录页面对象
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");
替代方法
我希望有一种更清晰的方式来公开返回相关PageObject的单个方法,而不是复制代码。login()
我想过创建一个页面层次结构(或者让它们实现一个接口),以便我可以将其用作返回类型,但它感觉很笨拙。我想出了以下几点:
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);
这是灵活的 - 您可以添加一个过期的Password页面,而不必更改方法 - 只需添加另一个测试并通过相应的过期凭据和过期Password页面作为预期页面。login()
当然,您可以非常轻松地保留 and 方法,并将其内容替换为对泛型的调用(然后将其设为私有)。然后,新页面(例如过期密码页面)将需要另一种方法(例如)。loginAsAdmin()
loginAsCustomer()
login()
loginWithExpiredPassword()
这样做的好处是,方法名称实际上意味着什么(你可以很容易地看到登录有3种可能的结果),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 代码,并为数据/页面对象的每种排列公开许多不同的方法?