前言
上一小节我们已经学习了Page Object设计模式,优势很明显,能更好的体现java的面向对象思想和封装特性。但同时也存在一些不足之处,那就是随着这种模式使用,随着元素定位获取,元素定位与页面操作方法都在一个类里维护,会造成代码冗余度过高。
相信使用过spring的同学肯定都知道,基于注解方式的开发,会大大提高开发效率,使代码块变得相对整洁,清晰。
本小节要介绍的就是PageFactory 设计模式,同Page Object思想大体差不多,只是表现形式不太一样,只是通过注解方式来定位元素对象。
一、@FindBy和@CacheLookup用法
元素声明的写法:
//定位 密码输入框 @FindBy(name = "loginpassword") @CacheLookup private WebElement passWord;
注解说明:
@FindBy:这个注解的意思是说我们所查找的元素是以什么方式定位,
@CacheLookup:这个注解的意思是说找到元素之后将缓存元素,重复的使用这些元素,将会大大加快测试的速度。
WebElement passWord:就是变量名
二、PageFactory类使用
PageFactory提供的是静态方法,可以直接调用,一般在用完@FindBy后,需要进行元素初始化,则需要调用initElements(driver,this);方法。
三、使用 PageFactory 模式来分离页面元素
此处演示还沿用page object模式的风格,这里我又加了一层自己暂时定义叫基础层,现在就变成了四层:
下面将举例说明Page Object设计模式,我们还有360影视页面为例,来做进一步讲解。
1、基础层
先创建一个包,名为com.pagefactory.demo,接着在这个包下创建一个类名为HomePage,具体示例代码如下:
import org.openqa.selenium.WebDriver; org.openqa.selenium.chrome.ChromeDriver; org.openqa.selenium.support.PageFactory; /** * @author rongrong * 基础页面 */ public class HomePage { private static WebDriver driver; * * 用来传递WebDriver * @return */ WebDriver driver() { return driver; } public HomePage() { 设置系统变量,并设置chromedriver的路径为系统属性值 System.setProperty("webdriver.chrome.driver","tool/chromedriver.exe"); 实例ChromeDriver driver = new ChromeDriver(); PageFactory.initElements(driver,this); } * 打开浏览器 void open() { driver.get("https://i.360kan.com/login" * 关闭浏览器 close() { driver.quit(); } LoginPage loginPage() { LoginPage loginPage = LoginPage(); loginPage; } }
这是我的基础页面,为了让driver抽离出去
2、对象层
接着我们再来创建一个类,名为LoginPage,具体示例代码如下:
org.openqa.selenium.WebElement; org.openqa.selenium.support.CacheLookup; org.openqa.selenium.support.FindBy; org.openqa.selenium.support.How; rongrong * 对象库层代码案例 LoginPage { LoginPage(){ PageFactory.initElements(HomePage.driver(),1)">定位 用户名输入框 @FindBy(how = How.NAME,using = "loginname")第一种写法 @CacheLookup private WebElement userName; 定位 密码输入框 @FindBy(name = "loginpassword")第二种写法 WebElement passWord; 定位 登录按钮 @FindBy(linkText = "立即登录" WebElement loginBtn; 定位 提示错误信息 @FindBy(css = "[class='b-signin-error js-b-signin-error error-2']" WebElement errorMsg; WebElement getUserName() { userName; } WebElement getPassWord() { passWord; } WebElement getLoginBtn() { loginBtn; } WebElement getErrorMsg() { errorMsg; } * 用户名输入操作 * * @param userName sendKeysUserName(String userName) { getUserName().clear(); getUserName().sendKeys(userName); } * 密码输入操作 * * passWord sendKeysPassWord(String passWord) { getPassWord().clear(); getPassWord().sendKeys(passWord); } }
3、操作层
接着我们再来创建一个类,名为LoginMovies,用来记录登录的一系列操作,具体示例代码如下:
package com.demo; org.testng.Assert; rongrong * 操作层代码案例 LoginMovies { * * 登录过程 * userName * pwd * expected loginByPageFactory(String userName,String pwd,String expected) { HomePage homePage = HomePage(); 打开登录页 homePage.open(); 输入用户名 homePage.loginPage().sendKeysUserName(userName); 输入密码 homePage.loginPage().sendKeysPassWord(pwd); 点击登录 homePage.loginPage().getLoginBtn().click(); 获取提示语操作 String msg = homePage.loginPage().getErrorMsg().getText(); 验证输入手机号错误是否提示 Assert.assertEquals(msg,expected); 关闭浏览器 homePage.close(); } }
4、业务层
最后我们再来创建一个类,名为TestPageFactory,用来验证登录功能,具体示例代码如下:
org.testng.annotations.Test; rongrong * 业务层代码案例 TestPageFactory { * 测试登录 */ @Test textLogin() { 实例化操作对象 LoginMovies loginMovies = LoginMovies(); 登录操作 loginMovies.loginByPageFactory("your userName","your passWord","输入手机号不合法"); } }
从以上代码看,如果页面元素发生变化,我们在对应类里修改对应元素即可,而操作和业务层流程类及用例都不用改,如果仅是业务流程更改,只需要维护业务层流程类业务脚本,其他几个类都不用改,从而做到了很好的将页面、元素、脚本进行了分离。
关于PageObject & PageFactory的使用,这里仅为读者提供了思路,有兴趣的同学可以继续拓展,笔者能力有限,如果觉得文章好,还请添加关注我哦