页面对象模式理解
我有理解这种模式的问题。 首先,我想测试我的页面中的登录,我有一个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");
如果你知道确切位置您将被重定向到,您的submit
和performLogin
方法可以返回您的下一个页面对象的实例。
其他答案很好,并澄清您的问题。我想在这个答案中提出一个框架。
你的测试类不应该知道什么硒。它应该只与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例如。