webUI自动化测试框架(三):代码分层-对象库层

前言:做UI自动化,不可避免的要和页面上的元素打交道,有的童鞋可能会选择把页面元素的定位,操作都写在测试代码中,当页面元素比较少,测试代码比较少的情况下还好,但是一旦页面元素多起来(实际运用中也不太可能少),测试代码一多,就难以阅读和维护了,因为元素定位的代码并不能直接体现我要定位的是哪个元素,当页面元素变更了,我要去代码中找到该元素定位的代码也是比较困难的,这样就带了维护问题。

这里引入我们这个框架主要的设计理念:PO模式,这个我也是学习的大牛前辈,PO模式全称为Page Object模式,是webdriver中的一种测试设计模式,主要是将每个页面设计为一个class,其中包含了页面中需要测试的元素(按钮,输入框等),这样在写脚本时,可以通过调用页面类来获取该页面的元素。并且,当该页面因为需求变更,带来的元素变更时,我们也不需要改测试代码,只需要改这个页面类就行了,从而使得测试代码与页面元素管理分离。这样就清晰多了,维护起来也很简单明了。

但是,如果页面多了,比如我一个后台系统,有100多个页面,总不能写100个类吧,那维护起来也够呛,所以我们基于PO模式,再将它改良一下。


如下,进入正题:

先看分层:


1.定义一个页面基础类,BasePage,因为所有的页面都有共同点,我们可以将他们抽象出来:每个页面都有元素,每个页面元素需要做的动作,该类主要要做的就是找到这些元素,并做出相应动作:

package com.etyero.object;

import java.util.HashMap;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.etyero.utils.LogUtil;
import com.etyero.utils.UIExecutorImpl;
import com.etyero.utils.XMLUtil;

/**
 * 基础页面类
 * 
 * @author ljl
 */
public class BasePage extends UIExecutorImpl {
	protected WebDriver driver;
	protected String pageName;// 页面名称
	protected String xmlPath;// 页面元素配置文件路径
	protected HashMap<String, Locator> locatorMap;//存储页面元素信息
	public LogUtil log;

	public BasePage(WebDriver driver, String pageName) throws Exception {
		super(driver);
		this.driver = driver;
		this.pageName = pageName;
		// 获取page.xml路径,page.xml在同级目录
		xmlPath = this.getClass().getResource("").getPath() + "page.xml";
		locatorMap = XMLUtil.readXMLDocument(xmlPath, pageName);
	}

	public void click(String locatorName) {
		super.click(getLocator(locatorName));
	}

	public void sendKey(String locatorName, String value) {
		super.sendKey(getLocator(locatorName), value);
	}

	public String getText(String locatorName) {
		return super.getText(getLocator(locatorName));
	}

	public WebElement getElement(String locatorName) {
		return super.getElement(getLocator(locatorName));
	}

	public boolean isElementDisplayed(String locatorName) {
		return super.isElementDisplayed(getLocator(locatorName));
	}

	public void switchWindow(String title) {
		super.switchWindow(title);
	}

	public void switchFrame(String locatorName) {
		super.switchFrame(getLocator(locatorName));
	}

	/**
	 * 根据locatorName返回对应的locator
	 * 
	 * @author ljl
	 */
	public Locator getLocator(String locatorName) {
		Locator locator = null;
		if (locatorMap != null) {
			locator = locatorMap.get(locatorName);
		}
		return locator;
	}
}

2.BasePage类中定义了一个变量,HashMap<String, Locator>  locatorMap,这个变量主要存放了页面元素信息,key为页面元素名称,是我们自己定义的,方便我们知道这个元素是干嘛的,locator 保存了这个元素的定位方式(如By.id,By.xpath),定位地址(如By.id时的id),等待时长:

package com.etyero.object;

/**
 * 封装页面元素,每个元素都有相应的定位地址(xpath路径或css或id),等待时间,定位方式,默认为By.xpath
 * 
 * @author ljl
 *
 */
public class Locator {
	private String address; // 定位地址
	private int waitSec; // 等待时间
	private ByType byType; // 定位方式

	/**
	 * 定位类型枚举
	 * 
	 * @author ljl
	 *
	 */
	public enum ByType {
		by, xpath, linkText, id, name, className
	}

	public Locator() {
	}

	/**
	 * Locator构造器,默认定位类型By.xpath,等待时长3s
	 * 
	 * @author ljl
	 * @param element
	 */
	public Locator(String address) {
		this.address = address;
		this.waitSec = 3;
		this.byType = ByType.xpath;
	}

	public Locator(String address, int waitSec) {
		this.waitSec = waitSec;
		this.address = address;
		this.byType = ByType.xpath;
	}

	public Locator(String address, int waitSec, ByType byType) {
		this.waitSec = waitSec;
		this.address = address;
		this.byType = byType;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public int getWaitSec() {
		return waitSec;
	}

	public void setWaitSec(int waitSec) {
		this.waitSec = waitSec;
	}

	public ByType getByType() {
		return byType;
	}

	public void setByType(ByType byType) {
		this.byType = byType;
	}

}

3.有了BasePage和Locator类,但是我们的页面元素怎么管理呢,这里我们就要用到xml文件了,我们将要测试的页面定义为一个page节点,每个page节点对应一个页面,这样就不用写100个类了;每个page节点下,放该页面要测试的元素,每个元素我们给他定义好定位方式,定位地址,等待时长,以及元素名称,元素名称是为了方便我们知道这个元素是干嘛的,能快速找到该元素进行维护。page.xml如下:

<?xml version="1.0" encoding="UTF-8"?>

<map>
	
	<page pageName="mainPage">
		<!--Locator lists -->
		<locator type="xpth" timeOut="30" value="/html/body/div[1]/div[7]">客服热线</locator>
	</page>
	
	<page pageName="minePage">
		<!--Locator lists -->
		<locator type="id" timeOut="3" value="icon_user">用户头像</locator>
		<locator type="id" timeOut="3" value="user_name">用户名</locator>						
	</page>
		
	<page pageName="loginPage">
		<!--Locator lists -->
		<locator type="id" timeOut="30" value="txtuser">登录输入账号框</locator>
		<locator type="id" timeOut="30" value="txtuserp">登录输入密码框</locator>
		<locator type="id" timeOut="30" value="btnLogin">登录</locator>
		<locator type="id" timeOut="30" value="spanMessge">错误提示</locator>
	</page>
</map>

举个栗子:如上的loginPage,有账号,密码,登录按钮,错误提示四个要测试的元素,我们给账号元素定义了一个locator标签,对应的定位方式为用id定位,id的值为txtuser,等待时长30s,该元素名称我们给它取名为登录输入账号框,这样,当登录框的地址变了,我们可以快速找到,这个是登录的账号框,改掉id就行了。另外,解析xml文件用我们第二章中基础层的XMLUtil类方法。各司其职,清晰明了。

以上,对PO模式做了一个简单的改良,不用再写那么多页面类了,这也是我在大牛那学习的皮毛,相信有更好的方法,希望各位童鞋可以积极交流。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章