页面对象(Page Object)模式
内容转载自 https://www.cnblogs.com/yytesting/p/6973474.html
页面对象(Page Object)模式是目前自动化测试领域普遍使用的设计模式之一,此模式可以大大提高测试代码的复用率,提高测试脚本的编写效率和维护效率,是中级自动化测试工程师的必备技能之一。
使用面向对象的设计模式,页面对象模型将测试代码和被测试页面的页面元素及其操作方法进行分离,以此降低页面元素变化对测试代码的影响。每一个被测试页面都会被单独定义为一个类,类中会定位所有需进行测试操作的页面元素对象,并且定义操作每一个页面元素对象的方法。
例如,登录页面包括一个用户输入框和一个密码输入框,还有一个登录按钮。
我们声明一个名为Login的类,并且通过定位表达式找到用户名和密码输入框,并赋予类中的成员变量,分别定义输入用户名的方法、输入密码的方法和单击登录按钮的方法。
测试代码要完成登录测试,只需要调用Login类中输入用户名的方法、输入密码的方法和单击登录按钮的方法即可完成一个登录操作。如果登录页面的用户输入框、密码输入框或者登录按钮发生了位置变化,我们只需要修改Login类中的相关定位表达式和操作方法就可以完成维护,测试逻辑的脚本甚至不需要改变。
如果用户没有使用此模式,那么将登录过程都用相同的代码进行实现。如果在测试过程中需要多次登录操作,那么只能粘贴相同的代码来简化编写工作。但是可怕的情况是一旦页面元素发生了一点点改变,那么测试人员需要人工去把所有涉及变化的逻辑一一修改,会在不同的测试代码中进行搜索和修改,这样不但大大增加了工作量,而且很容易出现修改错误的情况。使用了页面对象模式,只需要修改一下唯一的Login类,就完成了大部分的维护工作。
测试网址:https://www.126.com/
使用PageFactory类
1.使用PageFactory类给测试类提供待操作的页面元素
先在src中新建一个package,名字为pageobjects,在下面新建一个页面对象类LoginPage。新建一个package,名字为testScripts,在下面新建一个测试类Test126mail。
LoginPage类的源代码如下:
public class LoginPage1 {
//使用FindBy注解,定位到需要操作的页面元素
@FindBy(name="email")
public WebElement userName;
@FindBy(name="password")
public WebElement password;
@FindBy(id="dologin")
public WebElement loginButton;
public LoginPage1(WebDriver driver) {
PageFactory.initElements(driver, this);
} }
Test126mail类的源代码如下:
public class Test126mail1 { private WebDriver driver;
private String baseUrl = "https://www.126.com/";
@Test
public void testLogin() throws InterruptedException {
//访问被测试的网址
driver.get(baseUrl);
Thread.sleep();
driver.switchTo().frame();
//生成一个LoginPage的实例
LoginPage1 loginPage = new LoginPage1(driver);
//直接使用页面对象的用户元素,输入用户名
loginPage.userName.sendKeys("邮箱名");
//直接使用页面对象的用户元素,输入密码
loginPage.password.sendKeys("邮箱密码");
//直接使用页面对象的登录按钮对象,进行单击操作
loginPage.loginButton.click();
//等待5秒
Thread.sleep();
driver.switchTo().defaultContent();
//断言登录后的页面是否包含"收件箱"关键字,来验证是否登录成功
Assert.assertTrue(driver.getPageSource().contains("收件箱"));
Thread.sleep();
} @BeforeMethod
public void beforeMethod() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\lenovo\\AppData\\Local\\Google\\Chrome\\chromedriver.exe");
driver = new ChromeDriver();
} @AfterMethod
public void afterMethod() {
/*driver.quit();*/
}
}
从上面的实例中我们可以看到,页面元素的定位均在LoginPage类中实现了。如果页面元素发生了一定程度的调整,测试人员只需要修改LoginPage类中的定位表达式就可以完成基本的维护工作,测试类代码无需进行调整,从而降低了测试代码的维护工作。
2.使用PageFactory类封装页面元素的操作方法
上面我们只为测试类提供了页面元素来进行操作,并没有在页面对象类中实现页面元素的操作方法。
LoginPage类的源代码如下:
public class LoginPage2 {
@FindBy(name="email")
public WebElement userName;
@FindBy(name="password")
public WebElement password;
@FindBy(id="dologin")
public WebElement loginButton;
public String url="https://www.126.com/";
public WebDriver driver;
//构造函数,生成浏览器对象,初始化PageFactory对象
public LoginPage2() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\lenovo\\AppData\\Local\\Google\\Chrome\\chromedriver.exe");
driver = new ChromeDriver();
PageFactory.initElements(driver, this);
} //访问被测试网址的封装方法
public void load() {
driver.get(url);
} //关闭浏览器的封装方法
public void quit() {
driver.quit();
} //登录操作的封装方法
public void login() throws InterruptedException {
Thread.sleep();
driver.switchTo().frame();
userName.sendKeys("邮箱用户名");
password.sendKeys("邮箱密码");
loginButton.click();
Thread.sleep();
driver.switchTo().defaultContent();
} public WebDriver getDirver() {
return driver;
} }
Test126mail的源代码如下:
public class Test126mail2 { @Test
public void testLogin() throws InterruptedException {
//生成一个LoginPage对象实例
LoginPage2 loginpage = new LoginPage2();
//调用登录页面对象的load方法,访问被测网页
loginpage.load();
//调用登录页面对象的login方法,完成登录操作
loginpage.login();
//断言登录后的页面是否包含"收件箱",来验证是否登录成功
//调用登录页面对象的getDriver方法获取浏览器对象,并获取页面源码
Assert.assertTrue(loginpage.getDirver().getPageSource().contains("收件箱"));
//调用登录页面对象的quit方法关闭浏览器
loginpage.quit();
}
}
在页面对象中封装了页面元素的操作方法,使得在测试代码中实现测试逻辑更加容易。这些封装方法可以被很多测试逻辑重复调用,从而提高了代码编写和维护的效率,实现了一个类维护,很多测试类可被调用的目的,进一步降低了测试代码的维护成本。
3.使用LoadableComponent类
继承LoadableComponent类可以在页面加载的时候判断是否加载了正确的页面,只需要重写isLoaded和load两个方法。此方式有助于让页面对象的页面访问操作更加健壮。
LoginPage类的源代码:
public class LoginPage3 extends LoadableComponent<LoginPage3>{ @FindBy(name="email")
public WebElement UserName;
@FindBy(name="password")
public WebElement password;
@FindBy(id="dologin")
public WebElement loginButton;
public String url ="https://www.126.com/";
private String title="网易邮箱";
public WebDriver driver;
//构造函数,生成浏览器对象,初始化PageFactory对象
public LoginPage3() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\lenovo\\AppData\\Local\\Google\\Chrome\\chromedriver.exe");
driver = new ChromeDriver();
PageFactory.initElements(driver, this);
} //访问被测试网址的封装方法
@Override
public void load() {
this.driver.get(url);
} //关闭浏览器的封装方法
public void quit() {
driver.quit();
} //登录操作的封装方法
public void login() throws InterruptedException {
Thread.sleep();
driver.switchTo().frame();
UserName.sendKeys("wuyn1315667459");
password.sendKeys("goodwu");
loginButton.click();
Thread.sleep();
driver.switchTo().defaultContent();
} public WebDriver getDriver() {
return driver;
} @Override
public void isLoaded() throws Error {
//断言登录后的页面title是否包含"网易邮箱"这几个关键字
Assert.assertTrue(driver.getTitle().contains(title));
} //增加了需要覆盖的方法load
//访问被测试网址的封装方法 }
Test126mail类的源代码:
public class Test126mail3 { @Test
public void testLogin() throws InterruptedException {
//生成一个LoginPage对象实例
LoginPage3 loginpage = new LoginPage3();
//
loginpage.load();
//调用登录页面对象的login方法,完成登录操作
loginpage.login();
//断言登录是否成功
loginpage.isLoaded();
//调用登录页面对象的quit方法关闭浏览器
loginpage.quit();
}
}
4.多个PageObject的自动化测试实例
本部分主要讲解多个PageObject的使用方法,以及如何基于多个PageObject实现一个相对复杂的自动化测试实例。
自动化测试实现的3个测试用例如下:
a.在126邮箱,使用正确的用户名和错误的密码进行登录,登录失败并在页面显示“帐号或密码错误”关键字。
b.在126邮箱,使用正确的用户名和正确的密码进行登录,登录成功后会跳转到邮箱文件夹列表首页,并且显示出“收件箱”关键字。
c.在126邮箱,登录成功后,单击“写信”链接,给testYY2017@126.com发送一封邮件,邮件发送成功后页面显示“发送成功”关键字。
LoginPage类:
public class LoginPage4 extends LoadableComponent<LoginPage4>{ @FindBy(name="email")
public WebElement userName;
@FindBy(name="password")
public WebElement password;
@FindBy(id="dologin")
public WebElement loginButton;
public String url ="https://www.126.com/";
private String title="网易邮箱";
public WebDriver driver; //构造函数,生成浏览器对象,初始化PageFactory对象
public LoginPage4(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
} //访问被测试网址的封装方法
@Override
public void load() {
this.driver.get(url);
this.driver.manage().window().maximize();
} public void close() {
this.driver.close();
} //登录操作的封装方法,函数方法返回一个HomePage对象
public HomePage login() throws InterruptedException {
//调用load方法,浏览器访问126邮箱页面
load();
WebDriverWait wait = new WebDriverWait(driver, );
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("iframe:first-child")));
driver.switchTo().frame();
//页面判断是否显示了用户名输入框
wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.name("email")));
//清除用户名输入框中的字符,保证用户名输入框中为空
userName.clear();
//输入邮箱用户名
userName.sendKeys("wuyn1315667459");
//输入密码
password.sendKeys("goodwu");
//单击登录按钮
loginButton.click();
Thread.sleep();
driver.switchTo().defaultContent();
return new HomePage(driver);
} //获取页面源码的封装方法
public String getPageSource() {
return driver.getPageSource();
} //登录失败的封装方法,函数方法返回一个LoginPage页面对象
public LoginPage4 LoginExceptingFailure() throws InterruptedException {
load();
WebDriverWait wait = new WebDriverWait(driver, );
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("iframe:first-child")));
driver.switchTo().frame();
userName.sendKeys("wuyn1315667459");
password.sendKeys("goodw");
loginButton.click();
Thread.sleep();
//driver.switchTo().defaultContent();
//登录失败后,页面不会发生跳转,返回一个LoginPage4对象
return new LoginPage4(driver);
} @Override
protected void isLoaded() throws Error {
// 断言登录后的页面标题是否包含"网易邮箱"这几个字
Assert.assertTrue(driver.getTitle().contains(title)); } }
HomePage类:
public class HomePage {
public WebDriver driver;
//写信
@FindBy(id="_mail_component_59_59")
public WebElement writeMailLink;
//邮件发送按钮
@FindBy(xpath="//*[contains(@id,'_mail_button_')]/span[contains(.,'发送')]")
public WebElement sendMailButton;
//收件人输入框
@FindBy(xpath="//*[contains(@id,'_mail_emailtips')]")
public WebElement receiver; public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this); } //写信的封装方法
public SendSuccessPage writeMail(){
WebDriverWait wait = new WebDriverWait(driver, );
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("_mail_component_59_59")));
//单击登录成功后页面上的"写信"链接
writeMailLink.click();
//进入写信页面,等待页面中收件人输入框加载出来
//wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(@id,'_mail_emailinput_')]/input")));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(@id,'_mail_emailtips')]"))); //收件人输入框获取焦点
receiver.click();
//调用粘贴函数在收件人输入框中粘贴
setAndCtrlVClipboardData("1315667459@qq.com");
//按tab键,焦点在邮件正文
pressTabKey();
//输入邮件主题
setAndCtrlVClipboardData("邮件主题");
pressTabKey();
//输入邮件正文
setAndCtrlVClipboardData("邮件正文");
//点击发送邮件按钮
sendMailButton.click();
return new SendSuccessPage(driver);
} //设定剪切板病进行字符串粘贴的封装方法
public static void setAndCtrlVClipboardData(String string) {
//模拟Ctrl+V进行粘贴操作
StringSelection selection = new StringSelection(string);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_V); try {
Thread.sleep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} //按tab键的封装方法
public static void pressTabKey() {
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
} public String getPageSource() {
return driver.getPageSource();
}
}
SendSuccessPage类:
public class SendSuccessPage {
public WebDriver driver; public SendSuccessPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
} public String getPageSource() {
return driver.getPageSource();
} public void close() {
this.driver.close();
} }
Test126mail类:
public class Test126mail4 { public WebDriver driver; @BeforeMethod
public void beforeMethod() {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\lenovo\\AppData\\Local\\Google\\Chrome\\chromedriver.exe");
driver = new ChromeDriver();
} @AfterMethod
public void afterMethod() {
driver.quit();
} //测试用例登录失败的测试用例
@Test
public void testLoginFail() throws InterruptedException {
//生成一个LoginPage对象
LoginPage4 loginPage = new LoginPage4(driver);
//继承LoadableCompinent类后,只要实现覆盖的load方法
//及时在没有定义get方法的情况下,也可以进行get方法的调用
//get方法会默认调用页面对象类中的load方法
//loginPage.get();
//调用LoginPage类中的登录失败方法
loginPage.LoginExceptingFailure();
//断言登录失败后的源代码中是否包含了'账号或密码错误'的关键字,调用LoginPage类中的getPageSource方法
//(注意:如果内容是在frame里,得切换到frame,才能通过PageSource获取到)
Assert.assertTrue(loginPage.getPageSource().contains("帐号或密码错误"));
//调用LoginPage对象中的close方法关闭浏览器 } //测试登录成功的测试用例
@Test
public void testLoginSuccess() throws InterruptedException {
LoginPage4 loginPage = new LoginPage4(driver);
//loginPage.get(); //loginPage.login()方法中已经访问了126网页,这边无需再重新访问
//调用LoginPage类中的login方法,登录成功后会跳转到邮箱登录后主页
//login函数会返回一个HomePage对象,以此来实现页面跳转到登录后主页
//以便实现在HomePage对象中进行相关的方法调用
HomePage homePage = loginPage.login();
//等待5秒,等待从登录页面跳转到邮箱登录后主页 Thread.sleep(); //断言登录成功后的源代码是否包含了“收件箱”的关键字,来验证是否登录成功
Assert.assertTrue(homePage.getPageSource().contains("收件箱")); loginPage.close();
} //测试发送邮件成功的测试用例
@Test
public void testwriteMail() throws InterruptedException {
LoginPage4 loginPage = new LoginPage4(driver);
HomePage homePage = loginPage.login();
//等待5秒,等待邮件发送完成
Thread.sleep();
//调用写邮件方法,完成在页面上的发送邮件操作
SendSuccessPage successPage = homePage.writeMail(); //等到五秒,等待邮件发送成功
Thread.sleep();
//断言邮件发送后,是否出二线"发送成功"4个字,以此验证邮件是否发送成功
Assert.assertTrue(successPage.getPageSource().contains("发送成功")); successPage.close();
}
}
遇见的问题:
1.登录错误用例中,断言页面是否包含“帐号或密码错误”,报错元素不存在
原因:该元素在iframe中必须切换进入iframe中,pageSource方法才能包含该元素
2.发送邮件成功用例中,定位收件人输入框,使用xpath定位://*[contains(@id,'_mail_emailinput_')]/input" ,报错,元素不可点击
unknown error: Element <input class="nui-editableAddr-ipt" type="text" role="combobox" tabindex=""
aria-label="收件人地址输入框,请输入邮件地址,多人时地址请以分号隔开"> is not clickable at point (, ).
Other element would receive the click: <label id="_mail_emailtips_0_214"
class="js-component-emailtips nui-ipt-placeholder">...</label>
使用覆盖元素,可以实现功能
设计原则
(1)在PageObject类中定义public方法来对外提供服务。
(2)不要暴露PageObject类中的内部逻辑。
(3)不要在PageObject类中进行断言操作。
(4)只需要在PageObject类中定义需要操作的元素和操作方法。
(5)PageObject页面中的相同动作如果会产生多个不同的结果,需要在PageObject类中定义多个操作方法。
页面对象(Page Object)模式的更多相关文章
- selenium page object模式
页面对象模式将测试代码和被测试页面的元素及操作进行分离,以降低页面元素的变化对测试代码的影响.每个被测试的页面都会被定义一个类,类中会定位元素和操作. 如果不使用page object模式,则相同的操 ...
- 转 Page Object模式
Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在Selenium测试页面中可以通 ...
- UI自动化测试的Page Object模式
在UI级的自动化测试框架中,当页面样式改变或者页面元素属性改变,那么代码也要随之进行修改,如何做到高效快速的修改代码来适应这些改变呢,这个时候可以引入Page Object模式,也是页面对象设计模式. ...
- 【C#|.NET】从细节出发(三) 逻辑层事务和page object模式
一. 业务逻辑层的事务问题 如果你的程序分层清晰并且系统禁用复杂存储过程,那么在DA中的职责比较单一.程序的逻辑通过BLL调用各种不同模块的DA来实现数据操作.如果当需要不同模块在一个事务的时候,问题 ...
- selenium 的页面对象模型Page Object
页面对象模型page object model是selenium中的一种脚本设计模式,它能将页面元素封装起来,与业务操作分隔开, 在页面变化改变时,无需去修改业务逻辑代码,提高脚本维护的效率. 1.p ...
- 浅析selenium的page object模式
selenium目前比较流行的设计模式就是page object,那么到底什么是page object呢,简单来说,就是把页面作为对象,在使用中传递页面对象,来使用页面对象中相应的成员或者方法,能更好 ...
- python+selenium自动化软件测试(第7章):Page Object模式
什么是Page ObjectModel模式Page Objects是selenium的一种测试设计模式,主要将每个页面看作是一个class.class的内容主要包括属性和方法,属性不难理解,就是这个页 ...
- 使用page object模式抓取几个主要城市的pm2.5并从小到大排序后写入txt文档
#coding=utf-8from time import sleepimport unittestfrom selenium import webdriverfrom selenium.webdri ...
- Page Object 模式编写UiAutomator脚本
在我们学习Page Object Model之前,我们先了解一下Page Object Model(以下简称POM). 为什么要POM 用UiAutomator启动UI自动化测试不是一件困难的任务.你 ...
- Selenium3+python自动化014-自动化常用设计模式页面对象模型 (Page Object)
一.概 念: PO(Page Object)设计模式是一种面向对象(页面对象)的设计模式,将测试对象及单个的测试步骤封装在每个Page对象中,以page为单位进行管理. 二.优点可以使代码复用,降低维 ...
随机推荐
- ORA-00600: 内部错误代码, 参数: [kcm_headroom_warn_1], [], [], [], [], [], [], [], [], [], [], []
SQL*Plus: Release 11.2.0.4.0 Production on 星期三 1月 1 08:53:48 2003 Copyright (c) 1982, 2013, Oracle. ...
- python selenium处理windows窗口
selenium本身处理不了windows窗口,需要借助,PyAutoit包 与autoit工具 这里以文件上传窗口为例: 1.安装python pyauto包 pip install PyAutoi ...
- vue中使用vue-quill-editor及上传图片到自己服务器
第一步,下载依赖 cnpm install vue-quill-editor --save 第二步,再main.js里引入组件(我这里是全局注册) // 富文本编辑器 import VueQuillE ...
- sublime快捷方式
- win7插着网线开机卡死,拔下网线开机正常
公司的部分win7电脑插着网线开机,进到桌面后网络图标转圈圈卡住.控制面板,启动项,任务管理器等都打不开.把网线拔下后再开机,电脑正常进入系统,后再插上网线就能正常上网了.被这个问题困扰了很久,百度也 ...
- html5 css练习,弹性三栏布局
*{ margin: 0; padding: 0;} body,html{ width: 100%; height: 100%; font: bold 24px ...
- WPF Combobox数据绑定 Binding
combobox数据绑定List链表集合区分显示值与选择的值 整体效果: 根据combobox选择情况分别打印选取值与显示值 代码: Windows窗体: <Window x:Class=&qu ...
- sql sugar
事务 using (var db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = Config.xxx, DbType ...
- ajax 防止重复提交
参考链接:http://www.hollischuang.com/archives/931 http://blog.csdn.net/everything1209/article/details/52 ...
- ubuntu+anaconda+mxnet环境配置
为了insightface和mxnet较劲的一天 mxnet环境: 官网下载pyhton2.7版本的anaconda,随便找个安装教程 sh Anacondaxxxx.sh #一路默认即可,第二个回车 ...