如何实现可以返回不同PageObjects的WebDriver PageObject方法 [英] How to implement WebDriver PageObject methods that can return different PageObjects

查看:112
本文介绍了如何实现可以返回不同PageObjects的WebDriver PageObject方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始使用 WebDriver ,我正在努力学习最佳做法,特别是使用 PageObjects PageFactory

I've just started using WebDriver, and I'm trying to learn the best practices, in particular using PageObjects and PageFactory.

我的理解是PageObjects应该公开各种操作一个网页,并将WebDriver代码与测试类隔离开来。通常,相同的操作可能会导致导航到不同的页面,具体取决于所使用的数据。

It's my understanding that PageObjects should expose the various operations on a web page, and isolate the WebDriver code from the test class. Quite often, the same operation can result in navigating to different pages depending on the data used.

例如,在这个假设的登录方案中,提供管理员凭据会将您带到AdminWelcome页面,并提供客户凭据将您带到CustomerWelcome页面。

For example, in this hypothetical Login scenario, providing admin credentials takes you to the AdminWelcome page, and providing Customer credentials takes you to the CustomerWelcome page.

因此,最简单的方法是公开两个返回不同PageObjects的方法...

So the easiest way to implement this is to expose two methods which return different PageObjects...

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);
    }

}

并在测试中执行以下操作class:

And do the following in the test 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。

Alternative approach

Instead of duplicating code, I was hoping there was a cleaner way of exposing a single login() method which returned the relevant PageObject.

我想创建一个页面层次结构(或让它们实现一个接口),这样我就可以使用它作为返回类型,但它感觉很笨拙。我想出的是:

I thought about creating a hierarchy of pages (or having them implement an interface) so that I could use that as the return type, but it feels clumsy. What I came up with was the following:

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

这意味着您可以在测试类中执行以下操作:

Which means you can do the following in the test class:

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页面作为预期页面传递。

This is flexible - you could add an ExpiredPassword page and not have to change the login() method at all - just add another test and pass in the appropriate expired credentials and the ExpiredPassword page as the expected page.

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

Of course, you could quite easily leave the loginAsAdmin() and loginAsCustomer() methods and replace their contents with a call to the generic login() (which would then be made private). A new page (e.g. the ExpiredPassword page) would then require another method (e.g. loginWithExpiredPassword()).

这有一个好处,方法名称实际意味着什么(你可以很容易地看到登录有3种可能的结果),PageObject的API更容易使用(没有预期的页面传入),但WebDriver代码仍在重复使用。

This has the benefit that the method names actually mean something (you can easily see that there are 3 possible results of logging in), the PageObject's API is a bit easier to use (no 'expected page' to pass in), but the WebDriver code is still being reused.

进一步改进......

如果你做了暴露单个 login()方法,通过向这些页面添加标记接口,可以更明显地通过登录到达哪些页面(如果没有必要,为每个场景公开一个方法。)

If you did expose the single login() method, you could make it more obvious which pages can be reached from logging in by adding a marker interface to those pages (this is probably not necessary if you expose a method for each scenario).

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);
}

这两种方法似乎运作良好,但我不确定它会如何缩放比较复杂的场景。我还没有看到任何类似的代码示例,所以我想知道当页面上的操作根据数据导致不同的结果时,其他人会怎么做?

Either approach seems to work well, but I'm not sure how it would scale for more complicated scenarios. I haven't seen any code examples like it, so I'm wondering what everyone else does when actions on a page can result in different outcomes depending on the data?

或者通常的做法是复制WebDriver代码并为数据/ PageObjects的每个排列公开许多不同的方法?

Or is it common practice to just duplicate the WebDriver code and expose lots of different methods for each permutation of data/PageObjects?

推荐答案

波希米亚人的答案不灵活 - 你不能让页面操作返回到同一页面(例如输入错误的密码),也不能超过1页导致不同页面的操作(如果登录页面有另一个导致不同结果的操作,请考虑一下你会有什么混乱)。为了迎合不同的结果,你最终还会有更多的PageObjects。

Bohemian's answer is not flexible - you cannot have a page action returning you to the same page (such as entering a bad password), nor can you have more than 1 page action resulting in different pages (think what a mess you'd have if the Login page had another action resulting in different outcomes). You also end up with heaps more PageObjects just to cater for different results.

在尝试了更多(包括失败的登录方案)后,我已经确定了以下:

After trialing this some more (and including the failed login scenario), I've settled on the following:

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);
}

这意味着你可以重用登录逻辑,但是不需要测试要传递预期页面的类,这意味着测试类非常易读:

This means you can reuse the login logic, but prevent the need for the test class to pass in the expected page, which means the test class is very readable:

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

为每个方案设置单独的方法也会使登录 PageObject的API非常清楚 - 并且很容易分辨登录的所有结果。我没有看到使用接口来限制<$ $使用的页面的任何价值c $ c> login()方法。

Having separate methods for each scenario also makes the Login PageObject's API very clear - and it's very easy to tell all of the outcomes of logging in. I didn't see any value in using interfaces to restrict the pages used with the login() method.

我同意Tom Anderson的说法,可重用的WebDriver代码应该重构为细粒度的方法。它们是否被细粒度暴露(因此测试类可以挑选和选择相关操作),或者作为单个粗粒度方法组合并暴露给测试类可能是个人偏好的问题。

I'd agree with Tom Anderson that reusable WebDriver code should be refactored into fine-grained methods. Whether they are exposed finely-grained (so the test class can pick and choose the relevant operations), or combined and exposed to the test class as a single coarsely-grained method is probably a matter of personal preference.

这篇关于如何实现可以返回不同PageObjects的WebDriver PageObject方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆