前言:该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);
//切换frame
public 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
*/
@Override
public void sendKey(Locator locator, String value) {
WebElement element = getElement(locator);
element.clear();
element.sendKeys(value);
}
@Override
public String getText(Locator locator) {
WebElement element = getElement(locator);
return element.getText();
}
/**
* 获取元素
*
* @author ljl
*
*/
@Override
public 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
*/
@Override
public boolean isElementDisplayed(Locator locator) {
boolean flag = false;
WebElement element = getElement(locator);
flag = element.isDisplayed();
return flag;
}
/**
* 切换窗口
*
* @author ljl
*/
@Override
public void switchWindow(String title) {
Set 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
*/
@Override
public void switchFrame(Locator locator) {
driver.switchTo().frame(locator.getAddress());
}
/**
* 智能等待,超过该时长抛出异常
*
* @author ljl
*/
@Override
public void waitElement(Locator locator) {
// TODO Auto-generated method stub
}
}
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;
}
}
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 readXMLDocument(String xmlUrl, String pageName) throws Exception {
LogUtil log = new LogUtil(XMLUtil.class);
HashMap locatorMap = new HashMap<>();
File file = new File(xmlUrl);
if (!file.exists()) {
log.error("can't find " + xmlUrl);
} else {
// 创建SAXReader对象
SAXReader sr = new SAXReader();
// 读取xml文件转换为Document
Document 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;
}
}
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();
}
}
}
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;
}
@Override
public void onTestSuccess(ITestResult tr) {
log.info("Test Success");
super.onTestSuccess(tr);
}
@Override
public 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");
}
@Override
public void onTestSkipped(ITestResult tr) {
log.error("Test Skipped");
super.onTestSkipped(tr);
}
@Override
public void onStart(ITestContext testContext) {
log.info("Test Start");
super.onStart(testContext);
}
@Override
public void onFinish(ITestContext testContext) {
log.info("Test Finish");
super.onFinish(testContext);
}
}