Java页面对象模型最佳实践 - 新对象

时间:2017-01-10 15:46:41

标签: java automation cucumber pageobjects

在Java页面对象模型中创建步骤时实例化对象的最佳方法是什么?

有谁知道如何编译Cucumber脚本?

我想如果所有内容都已构建并符合下面的第二或第三选项可能是最佳方法。

如果仅编译了与正在执行的测试相关的步骤,那么我认为它将是第一个。

我有以下例子:

private LoginPage loginPage = new LoginPage(driver);

@Given("^I have logged in as customer with two stored cards$")
public void iHaveLoggedInAsCustomerWithTwoStoredCards() throws Throwable {
    new HomePage(driver).clickLoginButton();
    loginPage.enterEmail("test@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

@Given("^I have logged in as customer with expired card$")
public void iHaveLoggedInAsCustomerWithExpiredCard() throws Throwable {
    new HomePage(driver).clickLoginButton();
    loginPage.enterEmail("test02@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

@Given("^the user logged in as customer with three stored cards$")
public void theUserLoggedInAsCustomerWithThreeStoredCards() throws Throwable {
    new HomePage(driver).clickLoginButton();
    loginPage.enterEmail("test03@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

以上所有步骤(在同一个LoginSteps.java类中加上更多步骤)都以

开头
new HomePage(driver).clickLoginButton();

这是最好的方法,还是创建单个实例更好?

private LoginPage loginPage = new LoginPage(driver);
private HomePage homePage = new HomePage(driver);

@Given("^I have logged in as customer with two stored cards$")
public void iHaveLoggedInAsCustomerWithTwoStoredCards() throws Throwable {
    homePage.clickLoginButton();
    loginPage.enterEmail("test@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

@Given("^I have logged in as customer with expired card$")
public void iHaveLoggedInAsCustomerWithExpiredCard() throws Throwable {
    homePage.clickLoginButton();
    loginPage.enterEmail("test02@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

@Given("^the user logged in as customer with three stored cards$")
public void theUserLoggedInAsCustomerWithThreeStoredCards() throws Throwable {
    homePage.clickLoginButton();
    loginPage.enterEmail("test03@test.com");
    loginPage.enterPassword("Password1");
    loginPage.clickLogin();        
}

或者,在“基础步骤”中实例化所有页面的效率更高。 LoginSteps扩展的类?

public class LoginSteps extends BaseSteps {
    @Given("^I have logged in as customer with two stored cards$")
    public void iHaveLoggedInAsCustomerWithTwoStoredCards() throws Throwable {
        homePage.clickLoginButton();
        loginPage.enterEmail("test@test.com");
        loginPage.enterPassword("Password1");
        loginPage.clickLogin();        
    }

    @Given("^I have logged in as customer with expired card$")
    public void iHaveLoggedInAsCustomerWithExpiredCard() throws Throwable {
        homePage.clickLoginButton();
        loginPage.enterEmail("test02@test.com");
        loginPage.enterPassword("Password1");
        loginPage.clickLogin();        
    }

    @Given("^the user logged in as customer with three stored cards$")
    public void theUserLoggedInAsCustomerWithThreeStoredCards() throws Throwable {
        homePage.clickLoginButton();
        loginPage.enterEmail("test03@test.com");
        loginPage.enterPassword("Password1");
        loginPage.clickLogin();        
    }
}

public baseSteps {

    protected LoginPage loginPage = new LoginPage(driver);
    protected HomePage homePage = new HomePage(driver);
}

2 个答案:

答案 0 :(得分:1)

我会进行基准测试,看看哪个版本效率最高。

如何编译Cucumber代码取决于您的构建工具。我会假设所有内容在使用之前都已编译。但是,一段时间后执行优化的JVM可能会在一段时间后表现不同。

我真的很想听听你为什么要考虑这个级别的表现?您是否希望一次执行此代码数小时?我的大多数场景很短,在第二个刻度上执行然后被抛弃。

答案 1 :(得分:1)

您的Cucumber测试是否针对GUI运行?如果是这样,无论您是创建单个实例还是创建给定页面对象的多个实例,它都不会有所作为。这种测试本质上是缓慢的,这样的调整将是难以察觉的。

无论情况如何,优先级应始终是一个好的设计。除了简化代码的未来维护之外,良好的设计还可以帮助您改进系统性能。但是,相反,情况并非如此。

黄瓜页面对象模型非常合适。但是它们应该安排在不同的层中,黄瓜位于页面对象模型之上,充当后者的客户端。观察您的代码示例我不明白为什么页面对象是作为步骤定义代码的一部分创建的。为什么clickLoginButton方法本身不返回LoginPage的实例?

在我看来,页面对象模型应该有两个基本原则支持:
1. API 。每个页面对象都应该使用与用户可以在该页面上执行的操作相对应的方法来定义API 2. 导航。每个操作都应该将用户带到同一页面或不同的页面。因此,每个方法都应返回Page Object本身或不同的Page Object。

第一个是由您的代码完成的,但不是第二个,或者至少它不够清楚。

我会认为HomePage和LoginPage类是这样的(没有太多细节):

public class HomePage
{
    public HomePage(WebDriver driver) {
        // ...
    }

    public LoginPage clickLoginButton() {
        perform click login button
        return new LoginPage(this.driver);
    }
}

public class LoginPage
{
    public LoginPage(WebDriver driver) {
        // ...
    }

    public LoginPage enterEmail(String email) {
        perform enter email
        return this;
    }

    public LoginPage enterPassword(String password) {
        perform enter password
        return this;
    }

    public NextPage clickLogin() {
        perform click login
        return new NextPage();
    }
}

对于Cucumber层,我会想到如下(再次,没有太多细节):

private static final String PASSWORD = "Password1";
private static final String EMAIL_CUSTOMER_WITH_TWO_STORED_CARDS = "test@test.com";
private static final String EMAIL_CUSTOMER_WITH_EXPIRED_CARD = "test02@test.com";
private static final String EMAIL_CUSTOMER_WITH_THREE_STORED_CARDS = "test03@test.com";

@Given("^I have logged in as customer with two stored cards$")
public void iHaveLoggedInAsCustomerWithTwoStoredCards() throws Throwable {
    this.performLogin(EMAIL_CUSTOMER_WITH_TWO_STORED_CARDS);
}

@Given("^I have logged in as customer with expired card$")
public void iHaveLoggedInAsCustomerWithExpiredCard() throws Throwable {
    this.performLogin(EMAIL_CUSTOMER_WITH_EXPIRED_CARD);
}

@Given("^the user logged in as customer with three stored cards$")
public void theUserLoggedInAsCustomerWithThreeStoredCards() throws Throwable {
    this.performLogin(EMAIL_CUSTOMER_WITH_THREE_STORED_CARDS);
}

private void performLogin(String email) {
    nextPage = homePage.clickLoginButton()
        .enterEmail(email)
        .enterPassword(PASSWORD)
        .clickLogin();
}

请参阅最后一个方法中的(可选)方法链接,作为页面对象模型方法返回的页面对象的结果。

我故意省略了变量homePage,loginPage和nextPage的声明。 LoginSteps不与其他Steps类共享变量,即使你从常见的BaseSteps类扩展它们,除非你将它们声明为静态:

public BaseSteps {
    protected static HomePage homePage;
    protected static LoginPage loginPage;
    protected static NextPage nextPage;
    ...
}

或者你可以考虑整合一个依赖注入框架,但我还没有尝试过。

将变量保持为私有实例属性不会起作用(即使它们不与其他Steps类共享),因为Cucumber使用类中包含的步骤定义为每个测试场景实例化Steps类。 / p>

最后,在Cucumber层中应该有一个钩子来初始化页面对象模型的入口点。

@Before
public void setUp() {
    homePage = new HomePage(driver);
}

这应该是从Cucumber层明确创建的唯一页面对象。