webUI自动化测试框架(二):代码分层-基础层

来源:互联网 发布:如何成为淘宝分销商 编辑:程序博客网 时间:2024/05/20 14:43

前言:该webUI自动化框架主要分为四层:基础层、对象层、操作层、用例层,每一层负责各自的功能,这样有益于提高代码的可读性,复用性和扩展性。基础层主要封装了一些工具类,如解析xml文件,读取excel,分浏览器启动,时间处理等,供其他类调用。

另外,笔者这边主要使用的第三方库有:

TestNG:负责断言、测试脚本的管理以及输出测试报告,安装及使用教程见笔者的另一篇博客:http://blog.csdn.net/u010798968/article/details/73549612

log4j:负责生成日志

dom4j:解析xml

代码大致结构如下图所示:



进入正题,介绍基础层各个核心类。

1.UIExecutor为一个接口,包含了若干个抽象方法,这些方法都是webdriver中常用的操作方法,如点击,获取文本,切换窗口等,后续有需要扩展的页面操作都可以在该接口中定义。

package com.etyero.utils;import org.openqa.selenium.WebElement;import com.etyero.object.Locator;/** * webDriver常见的API *  * @author ljl */public interface UIExecutor {    //点击public void click(Locator locator);//输入文本public void sendKey(Locator locator,String value);//获取元素文本public String getText(Locator locator);//获取元素public WebElement getElement(Locator locator) throws Exception;//判断元素是否显示public boolean isElementDisplayed(Locator locator);//切换页面public void switchWindow(String title);//切换framepublic void switchFrame(Locator locator);//智能等待public void waitElement(Locator locator);}
2.UIExecutor接口的实现类UIExecutorImpl:

package com.etyero.utils;import java.util.Set;import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.WebElement;import com.etyero.object.Locator;/** * UIExecutor接口实现类 *  * @author ljl */public class UIExecutorImpl implements UIExecutor {private WebDriver driver;public LogUtil log;public UIExecutorImpl(WebDriver driver) {this.driver = driver;}public WebDriver getDriver() {return driver;}public void setDriver(WebDriver driver) {this.driver = driver;}/** * 点击元素 *  * @author ljl * @param locator */public void click(Locator locator) {WebElement element = getElement(locator);element.click();}/** * 输入文本 *  * @author ljl */@Overridepublic void sendKey(Locator locator, String value) {WebElement element = getElement(locator);element.clear();element.sendKeys(value);}@Overridepublic String getText(Locator locator) {WebElement element = getElement(locator);return element.getText();}/** * 获取元素 *  * @author ljl *  */@Overridepublic WebElement getElement(Locator locator) {WebElement element = null;String address = locator.getAddress();//long tinkTime = locator.getWaitSec() * 1000;//try {//// 思考时间,等待元素加载//Thread.sleep(tinkTime);//} catch (InterruptedException e) {//e.printStackTrace();//}switch (locator.getByType()) {case xpath:element = driver.findElement(By.xpath(address));break;case id:element = driver.findElement(By.id(address));break;case className:element = driver.findElement(By.className(address));break;case linkText:element = driver.findElement(By.linkText(address));break;default:break;}return element;}/** * 元素是否显式显示 *  * @author ljl */@Overridepublic boolean isElementDisplayed(Locator locator) {boolean flag = false;WebElement element = getElement(locator);flag = element.isDisplayed();return flag;}/** * 切换窗口 *  * @author ljl */@Overridepublic void switchWindow(String title) {Set<String> handles = driver.getWindowHandles();for (String handle : handles) {if (handle.equals(driver.getWindowHandle())) {continue;} else {driver.switchTo().window(handle);if (title.contains(driver.getTitle())) {break;} else {continue;}}}}/** * 切换frame *  * @author ljl */@Overridepublic void switchFrame(Locator locator) {driver.switchTo().frame(locator.getAddress());}/** * 智能等待,超过该时长抛出异常 *  * @author ljl */@Overridepublic void waitElement(Locator locator) {// TODO Auto-generated method stub}}

3.BrowserUtil,浏览器工具类,用来返回不同的浏览器driver:

package com.etyero.utils;import java.util.concurrent.TimeUnit;import org.openqa.selenium.WebDriver;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.firefox.FirefoxDriver;import org.openqa.selenium.htmlunit.HtmlUnitDriver;import org.openqa.selenium.ie.InternetExplorerDriver;import org.openqa.selenium.remote.DesiredCapabilities;public class BrowserUtil {private static WebDriver driver;/** * 启动ie浏览器 *  * @param browserDriverUrl *            浏览器驱动url * @param sec *            所有页面操作的等待超时时长,此处为隐式等待,超时后找不到元素则抛出异常NoSuchElementException * @author ljl */public static WebDriver ie(String browserDriverUrl, long sec) {System.setProperty("webdriver.ie.driver", browserDriverUrl);// 关闭IE保护模式DesiredCapabilities ieCapabilities = DesiredCapabilities.internetExplorer();ieCapabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true);driver = new InternetExplorerDriver(ieCapabilities);driver.manage().window().maximize();driver.manage().timeouts().implicitlyWait(sec, TimeUnit.SECONDS);return driver;}/** * 启动chrome浏览器 *  * @param browserDriverUrl *            浏览器驱动url * @param sec *            所有页面操作的等待超时时长 * @author ljl */public static WebDriver chrome(String browserDriverUrl, long sec) {System.setProperty("webdriver.chrome.driver", browserDriverUrl);driver = new ChromeDriver();driver.manage().window().maximize();driver.manage().timeouts().implicitlyWait(sec, TimeUnit.SECONDS);return driver;}/** * 启动fireFox浏览器 *  * @param browserDriverUrl *            浏览器驱动url * @param sec *            所有页面操作的等待超时时长 * @author ljl */public static WebDriver fireFox(String browserDriverUrl, long sec) {System.setProperty("webdriver.firefox.bin", browserDriverUrl);driver = new FirefoxDriver();driver.manage().window().maximize();driver.manage().timeouts().implicitlyWait(sec, TimeUnit.SECONDS);return driver;}/** * 启动htmlUnitDriver,不会打开实际游览器,运行速度快 但当页面有负责js时,会定位不到元素,不建议使用 *  * @author ljl */public static WebDriver htmlUnitDriver(long sec) {driver = new HtmlUnitDriver();driver.manage().timeouts().implicitlyWait(sec, TimeUnit.SECONDS);return driver;}}

4.XMLUtil,因为我们的页面元素主要在xml文件中维护,这样可以做到页面元素和代码分离,如果页面元素有变,我们只需要修改xml文件即可,无需到代码中去一个个找,所以需要此工具类去解析xml文件得到页面元素的相关信息:


package com.etyero.utils;import java.io.File;import java.util.HashMap;import java.util.Iterator;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.etyero.object.Locator;import com.etyero.object.Locator.ByType;public class XMLUtil {/** * 读取页面配置文件 *  * @author ljl * @param xmlUrl *            页面配置文件路径 * @param pageName *            页面名称 */public static HashMap<String, Locator> readXMLDocument(String xmlUrl, String pageName) throws Exception {LogUtil log = new LogUtil(XMLUtil.class);HashMap<String, Locator> locatorMap = new HashMap<>();File file = new File(xmlUrl);if (!file.exists()) {log.error("can't find " + xmlUrl);} else {// 创建SAXReader对象SAXReader sr = new SAXReader();// 读取xml文件转换为DocumentDocument document = sr.read(file);// 获取所有根节点元素对象Element root = document.getRootElement();Iterator<?> rootIte = root.elementIterator();Locator locator = null;// 遍历根节点while (rootIte.hasNext()) {Element page = (Element) rootIte.next();log.info("pageName is " + pageName);// 忽略大小写比较if (page.attribute(0).getValue().equalsIgnoreCase(pageName)) {Iterator<?> pageIte = page.elementIterator();// 找到pageName后遍历该page内各个节点while (pageIte.hasNext()) {String type = "";String timeOut = "3";String value = "";String locatorName = "";Element locatorEle = (Element) pageIte.next();Iterator<?> locatorIte = locatorEle.attributeIterator();// 遍历单个标签内的元素while (locatorIte.hasNext()) {Attribute attribute = (Attribute) locatorIte.next();String attributeName = attribute.getName();if (attributeName.equals("type")) {type = attribute.getValue();} else if (attributeName.equals("timeOut")) {timeOut = attribute.getValue();} else {value = attribute.getValue();}}locator = new Locator(value, Integer.parseInt(timeOut), getByType(type));locatorName = locatorEle.getText();locatorMap.put(locatorName, locator);}break;}}}return locatorMap;}/** * 转换元素定位类型 *  * @author ljl */public static ByType getByType(String type) {ByType byType = ByType.xpath;if (type == null || type.equalsIgnoreCase("xpath")) {byType = ByType.xpath;} else if (type.equalsIgnoreCase("id")) {byType = ByType.id;} else if (type.equalsIgnoreCase("name")) {byType = ByType.name;} else if (type.equalsIgnoreCase("className")) {byType = ByType.className;}return byType;}}

5.ScreenShot,保存截图:

package com.etyero.utils;import java.io.File;import java.io.IOException;import org.apache.commons.io.FileUtils;import org.openqa.selenium.OutputType;import org.openqa.selenium.TakesScreenshot;import org.openqa.selenium.WebDriver;public class ScreenShot {private WebDriver driver;public ScreenShot(WebDriver driver) {this.driver = driver;}/** * 保存截图 *  * @param path *            截图保存路径 * @param shotName *            图片命名 *             * @author ljl */public void saveScreenShot(String path, String shotName) {LogUtil log = new LogUtil(ScreenShot.class);//TakesScreenshot接口是依赖于具体的浏览器API操作的,所以在HTMLUnit Driver中并不支持该操作TakesScreenshot tScreenshot = (TakesScreenshot)driver;// 截图File photo = tScreenshot.getScreenshotAs(OutputType.FILE);File shotFile = new File(path+shotName);try {// 将截图复制到指定目录FileUtils.copyFile(photo, shotFile);} catch (IOException e) {log.error(getClass() + " 保存截图失败");e.printStackTrace();}}}

6.TestNGListener,监听类,继承TestListenerAdapter,这里主要实现了监听测试过程并记录日志,以及如果测试失败,则保存截图。

package com.etyero.utils;import org.openqa.selenium.WebDriver;import org.testng.ITestContext;import org.testng.ITestResult;import org.testng.TestListenerAdapter;/** * 监听测试过程 *  * @author ljl */public class TestNGListener extends TestListenerAdapter {private static WebDriver driver;LogUtil log = new LogUtil(TestNGListener.class);public static void setDriver(WebDriver driver) {TestNGListener.driver = driver;}@Overridepublic void onTestSuccess(ITestResult tr) {log.info("Test Success");super.onTestSuccess(tr);}@Overridepublic void onTestFailure(ITestResult tr) {log.error("Test Failure");super.onTestFailure(tr);ScreenShot screenShot = new ScreenShot(driver);//获取当前project目录String path = System.getProperty("user.dir").replace("\\", "/");//加上时间戳以区分截图String curTime = TimeUtil.getDate("yyyyMMddHHmmss");screenShot.saveScreenShot(path + "/img/", "testFail" + curTime + ".png");}@Overridepublic void onTestSkipped(ITestResult tr) {log.error("Test Skipped");super.onTestSkipped(tr);}@Overridepublic void onStart(ITestContext testContext) {log.info("Test Start");super.onStart(testContext);}@Overridepublic void onFinish(ITestContext testContext) {log.info("Test Finish");super.onFinish(testContext);}}


以上,介绍了基础层的一些主要工具类,当然,除了这些,我们还可以封装一些其他常用的工具类,如时间转换,精度运算(java原生的double存在精度丢失问题),数据库连接等,也可以在这些工具类中继续扩展一些常用的方法。目的是达到代码的高重用性。

阅读全文
0 0