Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何实现可以返回不同PageObject的WebDriver PageObject方法_Java_Selenium_Webdriver_Pageobjects - Fatal编程技术网

Java 如何实现可以返回不同PageObject的WebDriver PageObject方法

Java 如何实现可以返回不同PageObject的WebDriver PageObject方法,java,selenium,webdriver,pageobjects,Java,Selenium,Webdriver,Pageobjects,我刚刚开始使用,我正在努力学习最佳实践,特别是使用和 据我所知,PageObjects应该公开网页上的各种操作,并将WebDriver代码与测试类隔离开来。通常,相同的操作会导致根据使用的数据导航到不同的页面 例如,在这个假设的登录场景中,提供管理员凭据将带您进入AdminWelcome页面,提供客户凭据将带您进入CustomerWelcome页面 所以实现这一点最简单的方法是公开两个返回不同PageObject的方法 登录页面对象 并在测试类中执行以下操作: Login loginPage =

我刚刚开始使用,我正在努力学习最佳实践,特别是使用和

据我所知,PageObjects应该公开网页上的各种操作,并将WebDriver代码与测试类隔离开来。通常,相同的操作会导致根据使用的数据导航到不同的页面

例如,在这个假设的登录场景中,提供管理员凭据将带您进入AdminWelcome页面,提供客户凭据将带您进入CustomerWelcome页面

所以实现这一点最简单的方法是公开两个返回不同PageObject的方法

登录页面对象 并在测试类中执行以下操作:

Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome = loginPage.loginAsAdmin("admin", "admin");
Login loginPage = PageFactory.initElements(driver, Login.class);
AdminWelcome adminWelcome = 
    loginPage.login("admin", "admin", AdminWelcome.class);

替代方法 我不希望重复代码,而是希望有一种更干净的方法公开一个
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);
}
private <T> T login(String user, String pw, Class<T> expectedPage){
    username.sendKeys(user);
    password.sendKeys(pw);
    submitButton.click();
    return PageFactory.initElements(driver, expectedPage);
}

public AdminWelcome loginAsAdmin(String user, String pw){
    return login(user, pw, AdminWelcome.class);
}

public CustomerWelcome loginAsCustomer(String user, String pw){
    return login(user, pw, CustomerWelcome.class);
}

public Login loginWithBadCredentials(String user, String pw){
    return login(user, pw, Login.class);
}

这是灵活的-您可以添加过期密码页面,而不必更改
login()
方法-只需添加另一个测试,并将相应的过期凭据和过期密码页面作为预期页面传递

当然,您可以很容易地离开
loginAsAdmin()
loginAsCustomer()
方法,并用对通用
login()
的调用替换它们的内容(然后将其设置为私有)。然后,新页面(例如ExpiredPassword页面)将需要另一种方法(例如
loginWithExpiredPassword()

这样做的好处是,方法名称实际上意味着什么(您可以很容易地看到登录有3种可能的结果),PageObject的API使用起来更容易一些(没有“预期的页面”传入),但WebDriver代码仍在被重用

进一步改进…

如果您确实公开了单个
login()
方法,则可以通过在这些页面上添加标记接口(如果您为每个场景公开了方法,则可能不需要这样做),从而使登录可以访问哪些页面变得更加明显

并将登录方法更新为:

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);
}
public T登录(字符串用户,字符串pw,
类(预期页){
用户名.sendKeys(用户);
密码。发送密钥(pw);
submitButton.click();
返回PageFactory.initElements(驱动程序,expectedPage);
}
这两种方法似乎都很有效,但我不确定它在更复杂的场景中如何扩展。我还没有看到任何类似的代码示例,所以我想知道,当页面上的操作根据数据可能导致不同的结果时,其他人会怎么做


或者只是复制WebDriver代码并为数据/页面对象的每个排列公开许多不同的方法是常见的做法吗?

您正在用多种类型污染您的API-只需使用泛型和继承:

public abstract class Login<T> {

    @FindBy(id = "username")
    private WebElement username;

    @FindBy(id = "password")
    private WebElement password;

    @FindBy(id = "submitButton")
    private WebElement submitButton;

    private WebDriver driver;

    private Class<T> clazz;

    protected Login(WebDriver driver, Class<T> clazz) {
        this.driver = driver;
        this.clazz = clazz
    }

    public T login(String user, String pw){
        username.sendKeys(user);
        password.sendKeys(pw);
        submitButton.click();
        return PageFactory.initElements(driver, clazz);
    }
}
公共抽象类登录{
@FindBy(id=“用户名”)
私有WebElement用户名;
@FindBy(id=“密码”)
私有WebElement密码;
@FindBy(id=“submitButton”)
私有WebElement提交按钮;
私有网络驱动程序;
私人课堂;
受保护的登录(WebDriver驱动程序,clazz类){
this.driver=driver;
this.clazz=clazz
}
公共T登录(字符串用户,字符串pw){
用户名.sendKeys(用户);
密码。发送密钥(pw);
submitButton.click();
返回PageFactory.initElements(驱动程序,clazz);
}
}
然后

public AdminLogin extends Login<AdminWelcome> {

   public AdminLogin(WebDriver driver) {
       super(driver, AdminWelcome.class);
   }
}

public CustomerLogin extends Login<CustomerWelcome> {

   public CustomerLogin(WebDriver driver) {
       super(driver, CustomerWelcome.class);
   }
}

public AdminLogin通过将类的实例传递到构造函数(称为“类型令牌”)中,扩展了能够将类的实例传递到
PageFactory.initElements()的登录模式。

波希米亚人的答案是不灵活的——你不能让一个页面操作将你返回到同一个页面(例如输入错误的密码),也不能让一个以上的页面操作导致不同的页面(想想如果登录页面有另一个操作导致不同的结果,你会有多么混乱)。为了满足不同的结果,你也会堆积更多的页面对象

在对此进行了一些测试(包括失败的登录场景)之后,我确定了以下几点:

public <T> T login(String user, String pw, Class<T> expectedPage){
    username.sendKeys(user);
    password.sendKeys(pw);
    submitButton.click();
    return PageFactory.initElements(driver, expectedPage);
}
private <T> T login(String user, String pw, Class<T> expectedPage){
    username.sendKeys(user);
    password.sendKeys(pw);
    submitButton.click();
    return PageFactory.initElements(driver, expectedPage);
}

public AdminWelcome loginAsAdmin(String user, String pw){
    return login(user, pw, AdminWelcome.class);
}

public CustomerWelcome loginAsCustomer(String user, String pw){
    return login(user, pw, CustomerWelcome.class);
}

public Login loginWithBadCredentials(String user, String pw){
    return login(user, pw, Login.class);
}
为每个场景提供单独的方法也使得
Login
PageObject的API非常清晰,并且很容易说出登录的所有结果。我没有看到使用接口限制
login()方法使用的页面有任何价值


我同意Tom Anderson的观点,即可重用的WebDriver代码应该重构为细粒度方法。它们是以细粒度的方式公开(这样测试类就可以选择相关的操作),还是作为一个单一的粗粒度方法组合并公开给测试类,这可能是个人偏好的问题。

这很好,但是,如果登录页面上有另一个操作可能导致不同的PageObject集(继承被锁定为1),则可能会受到限制。哦,您的登录构造函数缺少
this.clazz=clazz
:)另外,
PageObject
是自定义类/接口还是WebDriver/Selenium相关API的一部分?我在测试你的想法时删除了它,因为我的PageObjects没有扩展/实现任何东西。对不起-我猜PageObject是一个接口。。。但它不是,它是一个概念,所以它只是
而不是
。另外,修复了构造函数这个答案确实回答了另一个问题——如何编写泛型方法而不提供所需的类来返回。我真正想要的是编写能够返回不同结果的PageObject方法的最佳实践
public AdminLogin extends Login<AdminWelcome> {

   public AdminLogin(WebDriver driver) {
       super(driver, AdminWelcome.class);
   }
}

public CustomerLogin extends Login<CustomerWelcome> {

   public CustomerLogin(WebDriver driver) {
       super(driver, CustomerWelcome.class);
   }
}
private <T> T login(String user, String pw, Class<T> expectedPage){
    username.sendKeys(user);
    password.sendKeys(pw);
    submitButton.click();
    return PageFactory.initElements(driver, expectedPage);
}

public AdminWelcome loginAsAdmin(String user, String pw){
    return login(user, pw, AdminWelcome.class);
}

public CustomerWelcome loginAsCustomer(String user, String pw){
    return login(user, pw, CustomerWelcome.class);
}

public Login loginWithBadCredentials(String user, String pw){
    return login(user, pw, Login.class);
}
Login login = PageFactory.initElements(driver, Login.class);
login = login.loginWithBadCredentials("bad", "credentials");
// TODO assert login failure message
CustomerWelcome customerWelcome = login.loginAsCustomer("joe", "smith");
// TODO do customer things