Selenium WebDriver 數據驅動測試框架,以QQ郵箱添加聯繫人爲示例,測試框架結構以下圖,詳細內容請閱讀吳曉華編著《Selenium WebDiver 實戰寶典》:css
ObjectMap.javajava
/** * 使用配置文件存儲測試頁面上的定位和定位表達式,作到定位數據和程序的分離 */ 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.javaweb
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.javachrome
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.javaapache
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.javaapp
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.javaxss
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.javaide
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
QQ郵箱的測試數據.xlsx