到这节课为止我们已经基本上把WebDriver和TestNG的基础都讲完了,下去开始讲讲实战过程中我们会用到的一些思想和工具。
例如这节我们要讲的PageObject思想。相信如果现在你们的脚本已经经过几个迭代的修改了,你们一定会遇到一个头痛的问题,那就是页面变化,以前脚本的定位方式不能用了,得修改定位方式,那如果以往的脚本没有用PageObject思想,意味着你得一个一个Case中把需要修改的定位方式找出来,然后再进行修改。这不但照成脚本维护的成本加大,也可能照成大量代码冗余。
那这时候PageObject就显得尤为重要。 那什么是PageObject呢?
什么是PageObject思想
PageObject 见名思意,就是页面对象。说白就是把页面元素定位和页面元素操作分开。
PageObject在实战过程中我们回对脚本实现进行分层。通常做法是分三层:
- 对象库层
- 逻辑层
- 业务层
对象层用于存放我们的页面元素和一些特殊控件操作。逻辑层则是一些封装好的功能用例模块。业务层则是我们真正的测试用例的操作。
当然如果我们的测试数据量大时,我们还可以在三层基础上再加一层 数据层,用于存放我们的测试数据,这也是比较常规的做法。
- 对象库层
- 逻辑层
- 业务层
- 数据层
实战例子
废话不多说我们直接来看个例子,我们还是以163邮箱登录为例子。
对象库层
首先我们新建个叫LoginPage的类,编写登录页面所有可能需要操作的元素定位方式和操作,代码示例如下:
package com.selenium.pageobjcet;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
/**
* Created by 米阳 on 14/10/2017.
*/
public class LoginPage {
// 定位 ifrmae
public static By loginFrame = By.id("x-URS-iframe");
// 定位 邮箱地址输入框
public static By emailField = By.name("email");
// 定位 密码输入框
public static By pwdFiled = By.name("password");
// 定位 登录按钮
public static By loginBtn = By.id("dologin");
WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
}
/**
* 往邮箱文本框输入邮箱
* @param email 邮箱地址
*/
public void sendKeysEmail(String email) {
driver.findElement(emailField).clear();
driver.findElement(emailField).sendKeys(email);
}
/**
* 往密码文本框输入密码
* @param pwd 密码
*/
public void sendKeysPWD(String pwd) {
driver.findElement(pwdFiled).clear();
driver.findElement(pwdFiled).sendKeys(pwd);
}
}
这里我们只把邮件输入框和密码输入框的操作进行封装,当然如果为了便于阅读也可以把所有的元素操作进行封装取名。
操作层
我们再新建个叫LoginMail的类,用于登录逻辑封装,供业务层Case调用,实现如下:
package com.selenium.pageobjcet;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
/**
* Created by 米阳 on 14/10/2017.
*/
public class LoginMail {
WebDriver driver;
public LoginMail(WebDriver driver) {
this.driver = driver;
}
/**
* 登陆
*
* @param emial 邮箱地址
* @param pwd 密码
*/
public void login(String emial, String pwd) {
LoginPage loginPage = new LoginPage(driver);
WebElement element = driver.findElement(LoginPage.loginFrame);
driver.switchTo().frame(element);
loginPage.sendKeysEmail(emial);
loginPage.sendKeysPWD(pwd);
driver.findElement(LoginPage.loginBtn).click();
}
}
业务层
最后我们来看下业务层的封装,也就是我们真正Case的编写:
package com.selenium.pageobjcet;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.concurrent.TimeUnit;
/**
* Created by 米阳 on 14/10/2017.
*/
public class LoginTest {
WebDriver driver;
@BeforeClass
public void openChrome() {
System.setProperty("webdriver.chrome.driver", "./drivers/chromedriver.exe");
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
@Test
public void testLogin2() {
driver.get("http://mail.163.com/");
LoginMail loginMail = new LoginMail(driver);
loginMail.login("meyoungtester", "meyoung123");
}
@AfterClass
public void closedChrome() {
driver.quit();
}
}
小结
经过我们对登陆功能的改装,采用了PageObject思想后,假设以后要是登录页面的A元素变更,我们就不需要在工程里面到处找用到这个A元素的Case去修改他们的定位方式,我们只需要打开我们的LoginPage,找到A元素的定位方式,进行修改,则整个工程用到A元素定位的就自然而然的修改了。同样如果哪天登录流程变更了,例如登录过程必须输入验证码,那么我们也不需要把所有Case涉及到登录的都找出来,插入输入验证码过程,只需要在先在LoginPage里面登陆验证码的定位方式,接着加入打开LoginMail,在登录逻辑里面加入我们的验证码输入步骤,则用到登录逻辑的所有Case则不需要其他维护。
PageObject 的优点
一张图差不多对PO思想引入的前后对比。PO思想对界面交互细节进行了封装,这样可以使我们的自动化测试脚本案例更关注业务,而非界面细节,提高了测试案例的可读性。
PageFactory
PageFactory 整体思想同于PageObject思想,只是表象显示上不太一样,它通过注解的方式来定位元素对象,例如:
对象库层:
@FindBy(id = "kw")
public static WebElement emailName;
Case使用:
@Test
public void test(){
driver.get("https://www.baidu.com");
// 初始化 LoginPage
PageFactory.initElements(driver ,LoginPage.class);
LoginPage.emailName.sendKeys("Test");
}
PageObject VS PageFactor
WebDriver 提供了这两种元素对象管理的思想,总的来说没有谁好谁坏,看个人习惯,实际工程也可以两者结合使用。就个人而言更习惯PageObject思想,但PageFactor也不错,通过注解方式代码看起来更加简洁。