页面对象模式理解

页面对象模式理解

问题描述:

我有理解这种模式的问题。 首先,我想测试我的页面中的登录,我有一个LoginPage,它在成功验证后扩展了我的PageObject,它返回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(); 
    } 
} 

关于页面对象模型的一个优点是它是一个通用指南,而不是一个严格的系统。每个人都喜欢他们如何模拟他们的硒项目。

要回答你的直接问题,有一个页面对象的方法触发一个新的页面加载到浏览器中,返回一个表示该页面的新页面对象是完全有效的。

就每个单独的测试而言,除非您试图在一个测试间保存Web应用程序中的有状态信息(对于我来说这通常是一个坏主意),那么是的,您需要每次测试来重复此操作登录程序。但它不一定是重复的代码,将这个例程封装在一个方法中,每个测试都可以称为第一阶段的业务。此外,执行过程与测试过程不一样,您对登录页面的测试应该断言事情正确,需要以中间步骤登录的其他测试应该跳过这些断言。

另外,页面对象不需要封装整个页面。你想要考虑你正在测试的应用程序的设计。并非所有的应用程序都自动实现自动化,因此硒项目不应该具有普遍性。

如果您的应用程序是静态页面的集合,并没有发生状态变化,那么您可能希望每个网页都有一个页面对象。但是如果你有一个单独的页面应用程序,它只是让页面的大部分区域频繁出现和消失......也许你的页面对象可以更好地封装单个页面的区域,代表来去的组件或框架,但是在自己内部是一致的。

从概念的角度来看,您希望您的页面对象隐藏所有原始硒,以便您的测试不需要知道或关心,并提供一个简洁的公共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("[email protected]").enterPassword("12345").submit(); 

// Another way: 
loginPage.performLogin("[email protected]", "12345"); 

如果你知道确切位置您将被重定向到,您的submitperformLogin方法可以返回您的下一个页面对象的实例。

其他答案很好,并澄清您的问题。我想在这个答案中提出一个框架。

enter image description here

你的测试类不应该知道什么硒。它应该只与Page对象交互。页面对象通过页面片段与浏览器交互。页面片段处理webdriver。

正如您使用硒+ java,看看Arquillian - Graphene。它是一组库,可以帮助您在Java + Selenium中创建更好的框架。您可以添加库&只需选择不使用。基本上它不会搞乱你现有的脚本。

优点:

  • 你不需要页面工厂。一切都在运行时为你注入。包括司机。
  • AJAX处理
  • jQuery选择
  • AngularJS选择

还有更多。

对于例如:在你的情况,

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

} 

检查here例如。