当前位置: 首页 > 知识库问答 >
问题:

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

杨骏
2023-03-14

在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扩展的“baseSteps”类中实例化所有页面是否更有效?

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个答案

姬银龙
2023-03-14

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

不管是什么情况,优先考虑的总是一个好的设计。一个好的设计不仅可以简化代码的未来维护,还可以让您改进系统性能。然而,事实并非如此。

cucumber和页面对象模型非常适合。但是它们应该被安排在不同的层中,cucumber位于页面对象模型的顶部,作为后者的客户端。看着你的代码示例,我不明白为什么页面对象是作为步骤定义代码的一部分创建的。为什么clickLoginButton方法本身不返回LoginPage的实例?

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

第一个是由您的代码实现的,但不是第二个,或者至少它不够清晰。

我认为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();
}

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

我故意省略了变量home Page、loginPage和nextPage的声明。LoginSteps不会与其他Steps类共享变量,即使您使它们从公共BaseSteps类扩展,除非您声明它们为静态:

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

或者,您可以考虑集成依赖注入框架,但我自己还没有尝试过。

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

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

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

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

锺离鸿
2023-03-14

我将基准测试看看哪个版本最有效。

Cucumber代码的编译方式取决于您的构建工具。我假设所有东西在被使用之前都被编译过。但是,在执行某些操作后优化自身的JVM可能会在一段时间后表现不同。

我真的很想知道为什么你会考虑在这个水平上的表现?您希望一次执行此代码几个小时吗?我的大多数场景都很短,在第二个尺度上执行,然后扔掉。

 类似资料:
  • 我从0开始开发我的项目已经1年了。我的框架和测试已经达到了一定的“维护”水平。然而,每天我都在怀疑我是否在我的项目中使用了良好的实践。如果有经验的人能回答我的几个问题就好了。我主要对页面对象模式和页面工厂有疑问。 简要说明: 我的项目是一个基于一页的应用程序,用C#,angular编写。js,javascript。驱动程序是一个静态实例,它有很多额外的方法(在下面的代码中,我只展示了2)。每个页面

  • 我正在使用Perl和Selenium构建一个测试自动化项目。我正在使用页面对象模型。我有点不确定Selenium驱动程序将适合页面对象模型的实现。 每个页面对象是否应该“有”一个驱动程序?我的想法是,每个页面对象代表页面向用户提供的一组服务。考虑到这个概念,页面对象与驱动程序没有“has-a”关系。页面对象与驱动程序交互。不过,我仍在寻求建议。我应该将驱动程序作为web应用程序中每个页面对象的一部

  • 我目前正在改进一些旧的uni分配,将它们从可序列化文件转移到任何其他形式的存储,主要是SQL数据库。我理解关系数据库设计的概念以及与OOP类的相似之处,但是,我不完全确定如何从OOP设计的角度来处理这个问题。 现在我有一个酒店类,房间列表为属性,每个房间都有一个客人列表为属性(此处为完整代码) 回到使用文件时,我可以用Serializable接口标记这些类,并将父对象存储在单个文件中。但是当使用关

  • 我基本上有一个对象,它存储了一个项目的3D位置和其他属性,如速度。该位置每隔100毫秒由一个单独的威胁计算一次。另一种威胁访问这些属性并修改其中的一些属性。 我的第一个想法是简单地对每个属性使用,但据我所知,对volatile属性的每个操作都必须是原子的。由于这两种威胁都允许在某些情况下改变某些属性(如速度),这似乎不起作用。 我的下一个想法是使用Java的关键字,同步每个getter和sette

  • 我正在使用Selenium为我的网站构建一个测试框架,我实际上希望您在使用页面对象模型时对良好实践的想法:让我们说,我有一个欢迎页面,其中包含一个注销按钮存在的标题,这个标题可以在大多数页面中看到在我的页面中,我认为最好为标题写一个单独的类,比如: 公共类欢迎页 我的问题是,你认为在欢迎页面中包含标题作为属性更好还是应该将它们分开? 让我们以注销测试方法的代码为例: 案例一: 案例2: 第二个问题

  • 是否有任何Gem(比如siteprism:用于Web自动化测试)可以在我的移动自动化测试项目中使用,以使用页面对象模型模式定义屏幕。 提前谢谢