Selenium WebDriver 数据驱动测试框架

时间:2021-03-03 02:45:50

Selenium WebDriver 数据驱动测试框架,以QQ邮箱添加联系人为示例,测试框架结构如下图:

Selenium WebDriver 数据驱动测试框架

ObjectMap.java

/**
* 使用配置文件存储测试页面上的定位和定位表达式,做到定位数据和程序的分离
*/
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.openqa.selenium.By; public class ObjectMap { Properties properties; public ObjectMap(String propFile) {
properties = new Properties();
try {
FileInputStream in = new FileInputStream(propFile);
properties.load(in);
in.close();
} catch (IOException e) {
System.out.println("读取对象文件出错");
e.printStackTrace();
}
} public By getLocator(String ElementNameInpopFile) throws Exception {
// 根据变量ElementNameInpopFile,从属性配置文件中读取对应的配置对象
String locator = properties.getProperty(ElementNameInpopFile); // 将配置对象中的定位类型存储到locatorType变量,将定位表达式的值存储到locatorValue变量中
String locatorType = locator.split(":")[0];
String locatorValue = locator.split(":")[1]; // 在Eclipse中的配置文件均默认为ISO-8859-1编码存储,使用getBytes方法可以将字符串编码转换为UTF-8编码,以此来解决在配置文件读取中文乱码的问题
locatorValue = new String(locatorValue.getBytes("ISO-8859-1"), "UTF-8");
// 输出locatorType变量值和locatorValue变量值,验证是否赋值正确
System.out.println("获取的定位类型:" + locatorType + "\t 获取的定位表达式:" + locatorValue); // 根据locatorType的变量值内容判断返回何种定位方式的By对象
if (locatorType.toLowerCase().equals("id")) {
return By.id(locatorValue);
} else if (locatorType.toLowerCase().equals("name")) {
return By.name(locatorValue);
} else if ((locatorType.toLowerCase().equals("classname")) || (locatorType.toLowerCase().equals("class"))) {
return By.className(locatorValue);
} else if ((locatorType.toLowerCase().equals("tagname")) || (locatorType.toLowerCase().equals("tag"))) {
return By.className(locatorValue);
} else if ((locatorType.toLowerCase().equals("linktext")) || (locatorType.toLowerCase().equals("link"))) {
return By.linkText(locatorValue);
} else if (locatorType.toLowerCase().equals("partiallinktext")) {
return By.partialLinkText(locatorValue);
} else if ((locatorType.toLowerCase().equals("cssselector")) || (locatorType.toLowerCase().equals("css"))) {
return By.cssSelector(locatorValue);
} else if (locatorType.toLowerCase().equals("xpath")) {
return By.xpath(locatorValue);
} else {
throw new Exception("输入的 locator type 未在程序中被定义:" + locatorType);
}
}
}

Constant.java

public class Constant {

    //测试网址常量
public static final String URL = "http://mail.qq.com"; //测试数据EXCEL路径
public static final String TestDataExcelFilePath = "f:\\QQ邮箱的测试数据.xlsx"; //EXCEL测试数据sheet名称
public static final String TestDataExcelFileSheet = "新建联系人测试用例";
}

ExcelUntil.java

package until;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelUntil { private static XSSFSheet excelWSheet;
private static XSSFWorkbook excelWBook;
private static XSSFCell cell;
private static XSSFRow row; //指定要操作的excel文件的路径及sheet名称
public static void setExcelFile(String path,String sheetName) throws Exception{ FileInputStream excelFile;
try {
excelFile = new FileInputStream(path);
excelWBook = new XSSFWorkbook(excelFile);
excelWSheet = excelWBook.getSheet(sheetName);
} catch (Exception e) {
e.printStackTrace();
}
} //读取excel文件指定单元格数据(此方法只针对.xlsx后辍的Excel文件)
public static String getCellData(int rowNum,int colNum) throws Exception{
try {
//获取指定单元格对象
cell = excelWSheet.getRow(rowNum).getCell(colNum);
//获取单元格的内容
//如果为字符串类型,使用getStringCellValue()方法获取单元格内容,如果为数字类型,则用getNumericCellValue()获取单元格内容
String cellData = cell.getStringCellValue();
return cellData;
} catch (Exception e) {
return "";
}
} //在EXCEL的执行单元格中写入数据(此方法只针对.xlsx后辍的Excel文件) rowNum 行号,colNum 列号
public static void setCellData(int rowNum,int colNum,String Result) throws Exception{
try {
//获取行对象
row = excelWSheet.getRow(rowNum);
//如果单元格为空,则返回null
cell = row.getCell(colNum);
if(cell == null){
cell=row.createCell(colNum);
cell.setCellValue(Result);
}else{
cell.setCellValue(Result);
}
FileOutputStream out = new FileOutputStream(Constant.TestDataExcelFilePath);
//将内容写入excel中
excelWBook.write(out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
} //从EXCEL文件中获取测试数据
public static Object[][] getTestData(String excelFilePath,String sheetName) throws IOException{
//声明一个file文件对象
File file = new File(excelFilePath);
//创建一个输入流
FileInputStream in = new FileInputStream(file);
//声明workbook对象
Workbook workbook = null;
//判断文件扩展名
String fileExtensionName = excelFilePath.substring(excelFilePath.indexOf("."));
if(fileExtensionName.equals(".xlsx")){
workbook = new XSSFWorkbook(in);
}else {
workbook = new HSSFWorkbook(in);
} //获取sheet对象
Sheet sheet = workbook.getSheet(sheetName);
//获取sheet中数据的行数,行号从0始
int rowCount = sheet.getLastRowNum()-sheet.getFirstRowNum(); List<Object[]> records = new ArrayList<Object[]>();
//读取数据(省略第一行表头)
for(int i=1; i<rowCount+1; i++){
//获取行对象
Row row = sheet.getRow(i);
System.out.println(">>>>>>>>>>> "+ row.getLastCellNum());
//声明一个数组存每行的测试数据,excel最后两列不需传值
String[] fields = new String[row.getLastCellNum()-2];
//excel倒数第二列为Y,表示数据行要被测试脚本执行,否则不执行
if(row.getCell(row.getLastCellNum()-2).getStringCellValue().equals("Y")){
for(int j=0; j<row.getLastCellNum()-2; j++){
//判断单元格数据是数字还是字符
//fields[j] = row.getCell(j).getCellTypeEnum() == CellType.STRING ? row.getCell(j).getStringCellValue() : ""+row.getCell(j).getNumericCellValue();
fields[j] = row.getCell(j).getCellType() == CellType.STRING ? row.getCell(j).getStringCellValue() : ""+row.getCell(j).getNumericCellValue();
}
records.add(fields);
}
}
//将list转为Object二维数据
Object[][] results = new Object[records.size()][];
//设置二维数据每行的值,每行是一个object对象
for(int i=0; i<records.size(); i++){
results[i]=records.get(i);
}
return results;
} public static int getLastColumnNum(){
//返回数据文件最后一列的列号,如果有12列则返回11
return excelWSheet.getRow(0).getLastCellNum()-1;
}
}

Log.java

package until;

import org.apache.log4j.Logger;

public class Log {

    // 初始化Log4j日志
private static Logger Log = Logger.getLogger(Log.class.getName()); // 打印测试用例开头的日志
public static void startTestCase(String sTestCaseName) {
Log.info("------------------ " + sTestCaseName + " " +"开始执行 ------------------");
} //打印测试用例结束的日志
public static void endTestCase(String sTestCaseName) {
Log.info("------------------ " + sTestCaseName + " " +"测试执行结束 ---------------"); } public static void info(String message) {
Log.info(message);
} public static void warn(String message) {
Log.warn(message);
} public static void error(String message) {
Log.error(message);
} public static void fatal(String message) {
Log.fatal(message);
} public static void debug(String message) {
Log.debug(message);
} }

LoginPage.java

package pageobject;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import until.ObjectMap; public class LoginPage { private WebElement element = null;
//指定页面元素定位表达式配置文件的绝对路径
private ObjectMap objectMap = new ObjectMap("F:\\workspace\\TestNGProj\\ObjectMap.properties");
private WebDriver driver; public LoginPage(WebDriver driver){
this.driver = driver;
} //返回登录页面中的用户名输入框页面元素对象
public WebElement username() throws Exception{
element =driver.findElement(objectMap.getLocator("QQ.Email.username"));
return element;
} //返回登录页面中的密码输入框页面元素对象
public WebElement password() throws Exception {
element = driver.findElement(objectMap.getLocator("QQ.Email.password"));
return element;
} //返回登录页面中的登录按钮页面元素对象
public WebElement login_button() throws Exception {
element = driver.findElement(objectMap.getLocator("QQ.Email.login_button"));
return element;
}
}

HomePage.java

package pageobject;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import until.ObjectMap; public class HomePage { private WebElement element = null;
private ObjectMap objectMap = new ObjectMap("F:\\workspace\\TestNGProj\\ObjectMap.properties");
private WebDriver driver; public HomePage(WebDriver driver){
this.driver = driver;
} //获取登录后主页的“通讯录”链接
public WebElement addressLink() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.homepage.address_book"));
return element;
}
}

AddressBookPage.java

package pageobject;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import until.ObjectMap; public class AddressBookPage { private WebElement element = null;
private ObjectMap objectMap = new ObjectMap("F:\\workspace\\TestNGProj\\ObjectMap.properties");
private WebDriver driver; public AddressBookPage(WebDriver driver){
this.driver = driver;
} //获取新建联系人按钮
public WebElement addContactButton() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_button"));
return element;
} //新建联系人页面姓名输入框
public WebElement addContactName()throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_Contact"));
return element;
} //新建联系人页面邮件输入框
public WebElement addContactEmail() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_email"));
return element;
} //新建联系人页面电话输入框
public WebElement addContactTell() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_tell"));
return element;
} //新建联系人页面国家输入框
public WebElement addContactCounty() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_country"));
return element;
} //新建联系人页面省份输入框
public WebElement addContactProvince() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_province"));
return element;
} //新建联系人页面城市输入框
public WebElement addContactCity() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.add_city"));
return element;
} //新建联系人页面保存按钮
public WebElement addContactSaveButton() throws Exception{
element = driver.findElement(objectMap.getLocator("QQEmail.addressBook.save_button"));
return element;
}
}

LoginAction.java

package appmodules;

import org.openqa.selenium.WebDriver;
import org.testng.annotations.Test;
import pageobject.LoginPage;
import until.Log; /**
* 登录方法的封装,方便其他测试脚本的调用
*
*/
public class LoginAction { public static void execute(WebDriver driver,String userName,String passWord) throws Exception{
Log.info("访问网址:http://mail.qq.com");
driver.get("http://mail.qq.com");
driver.switchTo().frame("login_frame");
LoginPage loginPage = new LoginPage(driver);
loginPage.username().clear();
Log.info("在QQ邮箱登录页面的用户名输入框中输入 "+userName);
loginPage.username().sendKeys(userName);
Log.info("在QQ邮箱登录页面的密码输入框中输入 "+passWord);
loginPage.password().sendKeys(passWord);
Log.info("单击登录页面的登录按钮");
loginPage.login_button().click();
//Thread.sleep(5000);
}
}

AddContactAction.java

package appmodules;

import org.openqa.selenium.WebDriver;
import pageobject.AddressBookPage;
import pageobject.HomePage;
import until.Log; public class AddContactAction { public static void execute(
WebDriver driver,
String userName,
String passWord,
String contactName,
String contactEmail,
String contactCountry,
String contactProvince,
String contactCity) throws Exception{
//调用登录方法
Log.info("调用LoginAction类的execute方法");
LoginAction.execute(driver, userName, passWord);
Thread.sleep(3000); HomePage homePage = new HomePage(driver);
Log.info("登录后,单击通讯录链接");
homePage.addressLink().click();
driver.switchTo().frame("mainFrame"); AddressBookPage addressBookPage = new AddressBookPage(driver);
Log.info("休眠3秒,等待打开通讯录页面");
Thread.sleep(3000); Log.info("在通讯录页面,单击'新增联系人'按钮");
addressBookPage.addContactButton().click(); Log.info("在联系人姓名输入框中,输入: "+contactName);
addressBookPage.addContactName().sendKeys(contactName);
Log.info("在联系人邮箱输入框中,输入: "+contactEmail);
addressBookPage.addContactEmail().sendKeys(contactEmail);
//addressBookPage.addContactTell().sendKeys(contactTell);
Log.info("在联系人国家输入框中,输入: "+contactCountry);
addressBookPage.addContactCounty().sendKeys(contactCountry);
Log.info("在联系人省份输入框中,输入: "+contactProvince);
addressBookPage.addContactProvince().sendKeys(contactProvince);
Log.info("在联系人城市输入框中,输入: "+contactCity);
addressBookPage.addContactCity().sendKeys(contactCity);
Log.info("单击确定按钮");
addressBookPage.addContactSaveButton().click();
Log.info("休眠5秒,等待保存联系人后返回通讯录的主页面");
Thread.sleep(5000);
}
}

TestQQEmailAddContact.java

package testscript;

import java.io.IOException;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import appmodules.AddContactAction;
import until.Constant;
import until.ExcelUntil;
import until.Log; public class TestQQEmailAddContact { public WebDriver driver;
//调用Constant类中的常量url
private String url = Constant.URL; @DataProvider(name="testData")
public static Object[][] data() throws IOException{
//调用ExcelUntil工具类中getTestData()方法获取测试数据
return ExcelUntil.getTestData(Constant.TestDataExcelFilePath, Constant.TestDataExcelFileSheet);
} //使用名称为testData的dataProvider作为测试方法的测试数据集
//测试方法一共有12个参数,分别对应Excel数据文件中的1~12列
@Test(dataProvider="testData")
public void testAddressBook(
String caseRowNumber,
String testCaseName,
String userName,
String passWord,
String contactName,
String contactEmail,
String contactTell,
String contactCountry,
String contactProvince,
String contactCity,
String assertContactName,
String assertContactEmail
) throws Exception{
Log.startTestCase(testCaseName);
driver.get(url); Log.info("调用AddContactAction类的execute方法");
try {
AddContactAction.execute(driver, userName, passWord, contactName, contactEmail, contactCountry, contactProvince, contactCity);
} catch (AssertionError error) {
Log.info("添加联系人失败");
//设置Excel中测试数据行的执行结果为“测试执行失败”
ExcelUntil.setCellData(Integer.parseInt(caseRowNumber.split("[.]")[0]), ExcelUntil.getLastColumnNum(), "测试执行失败");
Assert.fail("执行AddContactAction类的execute方法失败");
}
Log.info("调用AddContactAction类的execute方法后,休眠3秒钟");
Thread.sleep(3000); Log.info("断言通讯录页面是否包含联系人姓名关键字");
try {
Assert.assertTrue(driver.getPageSource().contains(assertContactName));
} catch (AssertionError error) {
Log.info("断言通讯录页面是否包含联系人姓名的关键字失败");
ExcelUntil.setCellData(Integer.parseInt(caseRowNumber.split("[.]")[0]), ExcelUntil.getLastColumnNum(), "测试执行失败");
Assert.fail("断言通讯录页面是否包含联系人姓名的关键字失败");
} Log.info("断言通讯录页面是否包含联系人邮箱关键字");
try {
Assert.assertTrue(driver.getPageSource().contains(assertContactEmail));
} catch (AssertionError error) {
Log.info("断言通讯录页面是否包含联系人邮箱的关键字失败");
ExcelUntil.setCellData(Integer.parseInt(caseRowNumber.split("[.]")[0]), ExcelUntil.getLastColumnNum(), "测试执行失败");
Assert.fail("断言通讯录页面是否包含联系人邮箱的关键字失败");
} Log.info("新建联系人全部断言成功,在Excel的测试数据文件的'测试执行结果'中写入'测试执行成功'");
//断言全部成功,在Excel的测试数据文件的“测试执行结果”中写入“测试执行成功”
ExcelUntil.setCellData(Integer.parseInt(caseRowNumber.split("[.]")[0]), ExcelUntil.getLastColumnNum(), "测试执行成功");
Log.info("测试结果成功写入excel数据文件中的测试执行结果列");
Log.endTestCase(testCaseName); } @BeforeMethod
public void beforeMethod(){
System.setProperty("webdriver.chrome.driver", "e:\\chromedriver.exe");
driver = new ChromeDriver();
} @AfterMethod
public void afterMethod(){
driver.quit();
} @BeforeClass
public void BeforeClass() throws Exception{
ExcelUntil.setExcelFile(Constant.TestDataExcelFilePath,Constant.TestDataExcelFileSheet);
}
}

ObjectMap.properties

Selenium WebDriver 数据驱动测试框架

QQ邮箱的测试数据.xlsx

Selenium WebDriver 数据驱动测试框架