Java 页面对象模式理解

Java 页面对象模式理解,java,selenium-webdriver,Java,Selenium Webdriver,我无法理解这种模式。 首先,我想测试我的页面中的登录名,在成功验证后,我有一个扩展我的PageObject的LoginPage,它返回LoginPageReceipt。现在我有了loginPageReceipt,我想在第二页保留它。我想的第二个问题是,如果我首先测试登录,那么我想测试下一个模块,但我必须登录。我该怎么做?我的第二个测试不应该使用第一个测试的结果,我也不应该复制我的代码。这是我的课。我是怎么做到的 package Init; import org.junit.After; im

我无法理解这种模式。 首先,我想测试我的页面中的登录名,在成功验证后,我有一个扩展我的PageObject的LoginPage,它返回LoginPageReceipt。现在我有了loginPageReceipt,我想在第二页保留它。我想的第二个问题是,如果我首先测试登录,那么我想测试下一个模块,但我必须登录。我该怎么做?我的第二个测试不应该使用第一个测试的结果,我也不应该复制我的代码。这是我的课。我是怎么做到的

 package Init;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.concurrent.TimeUnit;

public class FunctionalTest {
    protected static WebDriver driver;
//    private static WebDriverWait driverWait;

    @BeforeClass
    public static void setUp() {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        System.setProperty("webdriver.chrome.driver", "src\\main\\resources\\chromedriver.exe");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//        driverWait = new WebDriverWait(driver, 10);
    }

    @After
    public void cleanUp() {
        driver.manage().deleteAllCookies();
    }

    @AfterClass
    public static void tearDown() {
        driver.close();
    }
}

package Init;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;

public class PageObject {

    protected WebDriver driver;

    public PageObject(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

}
package Login;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import Init.PageObject;

import static org.junit.Assert.assertTrue;

public class LoginPage extends PageObject {

    @FindBy(id = "UserName")
    private WebElement userName;

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

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

    public LoginPage(WebDriver driver) {
        super(driver);
        assertTrue(userName.isDisplayed());
        assertTrue(password.isDisplayed());
        assertTrue(loginButton.isDisplayed());
    }

    public void enterUserName(String userName) {
        this.userName.clear();
        this.userName.sendKeys(userName);
    }

    public void enterUserPassword(String password) {
        this.password.clear();
        this.password.sendKeys(password);
    }

    public LoginPageReceipt login() {
        loginButton.click();
        return new LoginPageReceipt(driver);
    }
}

package Contractor;

import Init.PageObject;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import static org.junit.Assert.assertTrue;

public class ContractorPage extends PageObject {

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

    public ContractorPage(WebDriver driver) {
        super(driver);
        assertTrue(moduleContent.isDisplayed());
    }
}

package Login;

import Contractor.ContractorPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import Init.PageObject;

public class LoginPageReceipt extends PageObject {

    @FindBy(xpath = "//*[@id=\"loginPartial\"]/span[5]")
    private WebElement userNamePanel;

    @FindBy(id = "contractors-menuitem")
    private WebElement goToContractorPage;

    public LoginPageReceipt(WebDriver driver) {
        super(driver);
    }

    public String loginConfirmation() {
        return  userNamePanel.getText();
    }

    public ContractorPage contractorPage() {
        goToContractorPage.click();
        return new ContractorPage(driver);
    }
}

package Tests;

import Login.LoginPage;
import Login.LoginPageReceipt;
import org.junit.Test;
import Init.FunctionalTest;

import static org.junit.Assert.assertEquals;

public class LoginTest extends FunctionalTest {

    private static final String USER_NAME = "xxx";
    private static final String PASSWORD = "xxx";

    @Test
    public void login() {
        FunctionalTest.driver.get("xxx");

        LoginPage loginPage = new LoginPage(FunctionalTest.driver);
        loginPage.enterUserName(USER_NAME);
        loginPage.enterUserPassword(PASSWORD);
        LoginPageReceipt loginPageReceipt = loginPage.login();

        assertEquals("Użytkownik: " + USER_NAME + " | Wyloguj", loginPageReceipt.loginConfirmation());
    }

}

package Tests;

import Contractor.ContractorPage;
import Init.FunctionalTest;
import Login.LoginPage;
import Login.LoginPageReceipt;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class ContractorTest extends FunctionalTest {

    private static final String USER_NAME = "xxx";
    private static final String PASSWORD = "xxx";

    @Test
    public void contractorPageTest() {
        FunctionalTest.driver.get("xxx");

        LoginPage loginPage = new LoginPage(FunctionalTest.driver);
        loginPage.enterUserName(USER_NAME);
        loginPage.enterUserPassword(PASSWORD);
        LoginPageReceipt loginPageReceipt = loginPage.login();

        assertEquals("Użytkownik: " + USER_NAME + " | Wyloguj", loginPageReceipt.loginConfirmation());

        ContractorPage contractorPage = loginPageReceipt.contractorPage();
    }
}

页面对象模型的一个优点是它是一个通用的指导原则,而不是一个僵化的系统。每个人都有自己对selenium项目建模的偏好

要回答您的直接问题,完全可以使用页面对象的方法触发浏览器中要加载的新页面,以返回表示该页面的新页面对象

对于每个单独的测试,除非您试图在一个测试到另一个测试之间保存web应用程序中的有状态信息(这对我来说通常是个坏主意),否则您将需要每个测试来重复此登录过程。但它不必是重复的代码,而是将该例程封装在一个方法中,每个测试都可以将该方法作为首要任务调用。此外,执行该过程与测试该过程不同,您对登录页面的测试应该断言事情是正确的,需要作为中间步骤登录的其他测试应该跳过这些断言

此外,页面对象不需要封装整个页面。你需要考虑你的设计与你正在测试的应用程序的关系。并不是所有的应用程序都是同样自动化的,所以selenium项目也不应该是通用的

如果您的应用程序是静态页面的集合,并且状态变化不大,那么您可能希望每个网页都有一个页面对象。但是,如果你有一个单页应用程序,它只不过是javascript,使得页面的大区域频繁出现和消失,那该怎么办呢。。。也许您的页面对象会更好地封装单个页面的区域,表示来来往往但内部一致的组件或框架

从概念的角度来看,您希望您的页面对象隐藏所有原始的selenium,这样您的测试就不需要知道或关心,并提供一个简洁的公共API,您的测试可以调用该API在该页面上执行操作

页面对象的方法是否封装了页面上的小动作,例如表单中每个字段的单独方法,或更大的工作流,例如填充整个表单并提交表单的方法,取决于您。这个决定应该考虑到应用程序的设计,你的目标是制作一款不仅可靠,而且易于创建新内容和维护现有内容的应用程序

编辑:

下面是一个理论登录页面对象的示例:

public class LoginPage {
    private final WebDriver driver;

    private final String emailField = "#email";
    private final String passwordField = "#password";
    private final String submitButton = "#submit";

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // These are our bite sized methods right here
    public LoginPage enterEmail(String email) {
        driver.findElement(By.cssSelector(emailField)).sendKeys(email);
        return this;
    }

    public LoginPage enterPassword(String password) {
        driver.findElement(By.cssSelector(passwordField)).sendKeys(password);
        return this;
    }

    public void submit() {
        driver.findElement(By.cssSelector(submitButton)).click();
    }

    // This method represents an entire workflow, 
    // containing multiple bite-sized chunks.
    public void performLogin(String email, String password) {
        enterEmail(email);
        enterPassword(password);
        submit();
    }
}
要使用,您的测试可以执行以下操作:

WebDriver driver = new ChromeDriver(options);
LoginPage loginPage = new LoginPage(driver);

//One way:
loginPage.enterEmail("my@email.com").enterPassword("12345").submit();

// Another way:
loginPage.performLogin("my@email.com", "12345");

如果您确切知道将重定向到哪里,您的
submit
performLogin
方法可以返回下一页对象的实例。

另一个答案很好,可以澄清您的问题。我想在这个回答中提出一个框架

您的测试类不应该知道关于selenium的任何内容。它应该只与页面对象交互。页面对象通过页面片段与浏览器交互。页面片段处理webdriver

当您使用selenium+java时,请看一看。它是一组libs,可以帮助您在Java+Selenium中创建更好的框架。您可以添加libs&只需选择不使用即可。基本上,它不会弄乱您现有的脚本

优势:

  • 您不需要页面工厂。一切都在运行时为您注射。包括司机
  • AJAX处理
  • JQuery选择器
  • 角度选择器
还有很多

对于前:在你的情况下

public class LoginPage  {
...
...
...
}


public class LoginPageReceipt {
...
...
...
} 



public class ContractorPage  {
...
...
...
}
测试班

public class LoginTest{

    @Page
    LoginPage loginPage;

    @Page
    LoginPageReceipt loginPageReceipt;

    @Test
    public void login() {
        loginPage.enterUserName(USER_NAME);
        loginPage.enterUserPassword(PASSWORD);
        loginPage.login();
        assertEquals("Użytkownik: " + USER_NAME + " | Wyloguj", loginPageReceipt.loginConfirmation());
    }

}
例如,检查