所用到的有:eclipse+maven+testng+log4j+Excel
在這里將以登錄163郵箱后新建聯系人作為例子
項目GitHub地址:https://github.com/puhongjun/seleniumDataDrierFrame.git
框架搭建步驟:
1、新建maven工程,在pom.xml文件中導入項目需要的jar包,需要導入的有 selenium-java,testng,log4j,poi和poi-ooxml。最后兩個是用於操作Excel的
2、在工程中新建4個Package,分別命名為:
cn.appModules:存放業務邏輯的封裝方法
cn.pageObjects:存放頁面元素
cn.testCase:存放測試用例
cn.util:存放工具類
3.在工程根目錄下新建一個log4j.xml文件存放log4j的配置信息,一個objectMap.properties文件存放頁面元素定位方式和定位表達式
pom.xml文件的內容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Selenium</groupId> <artifactId>DataFrameWork</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>DataFrameWork</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.53.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.testng/testng --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.9.9</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency> </dependencies> </project>
一、首先實現log4j打印日志功能
log4j.xml文件內容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" > <!-- 日志輸出到控制台 --> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <!-- 日志輸出格式 --> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d %-5p [%c{1}] %m %n"/> </layout> </appender> <!--定義了log4j將日志信息打印到日志文件,每天生成一個log文件--> <appender name="fileAppender" class="org.apache.log4j.DailyRollingFileAppender"> <!-- 定義日志信息級別為 info --> <param name="Threshold" value="INFO"/> <!-- 定義日志文件名為logs.log,日志文件與xml文件在同一文件夾下,若不存在則自動創建 --> <param name="File" value="logs/log4j.log"/> <layout class="org.apache.log4j.PatternLayout"> <!-- 定義日志格式 --> <param name= "ConversionPattern" value="%d %-5p [%c{1}] %m %n"/> </layout> </appender> <!-- 輸出到控制台和文件夾中的日志級別 --> <root> <priority value="info" /> <appender-ref ref="console" /> <appender-ref ref="fileAppender"/> </root> </log4j:configuration>
在cn.util包下新建log類,代碼如下
package cn.util;
import org.apache.log4j.Logger;
public class log {
//初始化Logger對象
private static Logger log=Logger.getLogger(log.class.getName());
//定義一個靜態方法,可以打印自定義的某個測試用例開始執行的日志信息
public static void startTestCase(String CaseName){
log.info("======================================================================");
log.info("************* "+CaseName+" 用例開始執行"+" *************");
}
//定義一個靜態方法,可以打印自定義的某個測試用例結束執行的日志信息
public static void endTestCase(String CaseName){
log.info("************* "+CaseName+" 用例執行結束"+" *************");
log.info("======================================================================");
}
//定義一個靜態info方法,打印自定義的info級別的日志信息
public static void info(String message){
log.info(message);
}
//定義一個靜態的warn方法,打印自定義的warn級別的日志信息
public static void warn(String message){
log.warn(message);
}
//定義一個靜態的error方法,打印自定義的error級別的日志信息
public static void error(String message){
log.error(message);
}
//定義一個靜態的fatal方法,打印自定義的fatal級別的日志信息
public static void fatal(String message){
log.fatal(message);
}
//定義一個靜態的debug方法,打印自定義的debug級別的日志信息
public static void debug(String message){
log.debug(message);
}
}
二、封裝截圖方法。在cn.util包下新建FileUtil工具類、DataUtil工具類和Screenshot類
FileUtil類代碼如下:
package cn.util; import java.io.File; import java.io.IOException; //FileUtil 類用於創建目錄和文件,此例子只是用此類的創建目錄的方法 public class FileUtil{ public static boolean createFile(String destFileName){ File file=new File(destFileName); if(file.exists()){ log.info("創建單個文件"+destFileName+"失敗,目標文件已存在!"); return false; } if(destFileName.endsWith(file.separator)){ log.info("創建單個文件"+destFileName+"失敗,目標文件不能為目錄!"); return false; } //判斷目標文件所在目錄是否存在 if(!file.getParentFile().exists()){ //如果目標文件所在的目錄不存在,則創建父目錄 log.info("目錄文件所在目錄不存在,准備創建它!"); if(!file.getParentFile().mkdirs()){ log.info("創建目標文件所在目錄失敗!"); return false; } } //創建目標問價 try{ if(file.createNewFile()){ log.info("創建單個文件"+destFileName+"成功!"); return true; }else{ log.info("創建單個文件"+destFileName+"失敗!"); return false; } }catch(IOException e){ e.printStackTrace(); log.info("創建單個文件"+destFileName+"失敗!"+e.getMessage()); return false; } } public static boolean createDir(String destDirName){ File dir=new File(destDirName); if(dir.exists()){ log.info("創建目錄"+destDirName+"失敗,目標目錄已存在"); return false; } //創建目錄 if(dir.mkdirs()){ log.info("創建目錄"+destDirName+"成功!"); return true; }else{ log.info("創建目錄"+destDirName+"失敗!"); return false; } } }
DataUtil類代碼如下:
package cn.util; import java.util.Date; //DataUtil類主要用於生成年、月、日、時、分、秒的信息,用於生成保存截圖文件目錄名和文件名 public class DataUtil{ //格式化輸入日期,@return 返回字符型日期 public static String format(java.util.Date date,String format){ String result=""; try{ if(date != null){ java.text.DateFormat df=new java.text.SimpleDateFormat(format); result=df.format(date); } }catch(Exception e){ e.printStackTrace(); } return result; } //返回年份 @return返回年份 public static int getYear(java.util.Date date){ java.util.Calendar c=java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.YEAR); } //返回月份 @return返回月份 public static int getMonth(java.util.Date date){ java.util.Calendar c= java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.MONTH)+1; } //返回在月份中的第幾天 @return返回月份中的第幾天 public static int getDay(java.util.Date date){ java.util.Calendar c= java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.DAY_OF_MONTH); } /* * 返回小時 * @param date * 日期 * @return返回小時 */ public static int getHour(java.util.Date date){ java.util.Calendar c=java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.HOUR_OF_DAY); } /* * 返回分鍾 * @param date * 日期 * @return返回分鍾 */ public static int getMinute(java.util.Date date){ java.util.Calendar c=java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.MINUTE); } /* * 返回秒 * @param date * 日期 * @return返回秒 */ public static int getSecond(java.util.Date date){ java.util.Calendar c=java.util.Calendar.getInstance(); c.setTime(date); return c.get(java.util.Calendar.SECOND); } }
Screenshot類實現截圖操作,代碼如下:
package cn.util; import java.io.File; import java.util.Date; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; public class Screenshot{ public static void method(WebDriver driver,String CaseName) { try{ //生成日期對象 Date date=new Date(); //調用DateUtil類中的方法,生成截圖所在的文件夾日期類型 String picDir="C:\\"+"errorScreenshot"+"\\"+String.valueOf(DataUtil.getYear(date))+"-" +String.valueOf(DataUtil.getMonth(date))+"-"+String.valueOf(DataUtil.getDay(date)); if(!new File(picDir).exists()){ FileUtil.createDir(picDir); } //調用DataUtil類中的方法,生成截圖文件的時間名稱 String filePath=picDir+"//"+String.valueOf(DataUtil.getHour(new Date()))+"時"+ String.valueOf(DataUtil.getMinute(new Date()))+"分"+ String.valueOf(DataUtil.getSecond(new Date()))+"秒"+CaseName+".png"; //進行截圖,並將文件內容保存在srcFile對象中 File srcFile=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); // File scrFile = new File(""); // scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); //將截圖文件內容寫入磁盤中,生成截圖文件 FileUtils.copyFile(srcFile, new File(filePath)); }catch(Exception e){ log.info("截圖失敗"); } } }
三、在cn.util包下新建ExcelUtil類,用於讀寫Excel表格。代碼如下:
package cn.util; 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 ExcelUtil { 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); //聲明一個數組存每行的測試數據,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; } }
四、封裝顯示等待方法(因為有些地方需要用到就做了個簡單的封裝)。在cn.util包下新建WaitMethod類,代碼如下:
package cn.util; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; //顯示等待封裝方法 public class WaitMethod { public static void xsWait(WebDriver driver,By by,int time){ try{ WebDriverWait wait=new WebDriverWait(driver,time); wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by)); }catch(NoSuchElementException e){ log.info("等待:"+time+"秒沒有找到 "+ by +" 元素"); Screenshot.method(driver,"顯示等待"+by+"元素"+time+"秒超時"); log.info("調用Screenshot.method方法截圖"); } } }
在cn.pageObjects包下新建WaitByElement類,代碼如下:(因為上面所寫的顯示等待方法需要傳入By類型的參數,這里為了方便就另寫了顯示等待需要傳入的幾個By類型元素)
package cn.pageObjects; import org.openqa.selenium.By; public class WaitByElement { //登錄界面的frame public static By loginFrame=By.xpath("//*[@id='loginDiv']/iframe[@frameborder='0']"); //首頁未讀郵件按鈕 public static By weiduButton=By.id("_mail_tabitem_0_3text"); //通訊錄頁面的 新建聯系人按鈕 public static By addLinMan=By.xpath("//span[text()='新建聯系人']"); //新建聯系人界面的 確定按鈕 public static By confirmButton=By.xpath("//div[@role='button']/span[text()='確 定']"); }
五、定位元素,這里使用UI Map定位元素,目的是能夠使用配置文件存儲被測頁面上元素的定位方式和定位表達式,做到定位數據和程序的分離。
在cn.util包下新建ObjectMap工具類,讀取objectMap.properties文件中配置頁面元素的定位表達式。代碼如下:
package cn.util; 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){ log.info("讀取文件對象出錯"); e.printStackTrace(); } } public By getLocator(String ElenmentNameInpropFile) throws Exception{ //根據變量ElenmentNameInpropFile,從屬性配置文件中讀取對應的配置對象 String locator=properties.getProperty(ElenmentNameInpropFile); //將配置對象中定位類型存儲到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變量值,驗證賦值是否正確 log.info("獲取的定位類型為:"+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.tagName(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 log.info("輸入的locator type未在程序中被定義:"+locatorType); throw new Exception("輸入的locator type未在程序中被定義:"+locatorType); } }
然后在新建的objectMap.properties文件中添加所需的元素定位方式和定位表達式,內容如下:
#登錄頁面 loginpage.intologin=id>lbNormal loginpage.loginframe=xpath>//*[@id='loginDiv']/iframe[@frameborder='0'] loginpage.username=name>email loginpage.password=name>password loginpage.loginbutton=id>dologin #首頁 homepage.shouyetext=id>_mail_tabitem_0_3text homepage.addressbook=id>_mail_tabitem_1_4text #通訊錄頁面 addressbookpage.addlinkman=xpath>//span[text()='新建聯系人'] #新建聯系人頁面 addressbookpage.name=id>input_N addressbookpage.email=xpath>//div[@id='iaddress_MAIL_wrap']/dl/dd/div/input addressbookpage.phonenumber=xpath>//div[@id='iaddress_TEL_wrap']/dl/dd/div/input addressbookpage.confirmbutton=xpath>//div[@role='button']/span[text()='確 定']
最后實現各個頁面元素的定位。在cn.pageObject包下新建LoginPage類實現登錄頁面各個元素的定位,代碼如下:
package cn.pageObjects; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import cn.util.ObjectMap; public class LoginPage { //指定頁面元素定位表達式配置文件的絕對路徑 private ObjectMap objectMap=new ObjectMap("F:\\Eclipse\\DataFrameWork\\objectMap.properties"); private WebElement element; private WebDriver driver; public LoginPage(WebDriver driver){ this.driver=driver; } //返回進入密碼登錄頁面元素對象 public WebElement intoLogin() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("loginpage.intologin")); return element; } //返回登錄頁面的frame元素對象 public WebElement loginFrame() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("loginpage.loginframe")); return element; } //返回登錄頁面用戶名輸入框元素對象 public WebElement userName() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("loginpage.username")); return element; } //返回登錄頁面密碼輸入框元素對象 public WebElement passWord() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("loginpage.password")); return element; } //返回登錄頁面登錄按鈕元素對象 public WebElement loginButton() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("loginpage.loginbutton")); return element; } }
在cn.pageObject包下新建HomePage類實現首頁各個元素的定位,代碼如下:
package cn.pageObjects; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import cn.util.ObjectMap; public class HomePage { //指定頁面元素定位表達式配置文件的絕對路徑 private ObjectMap objectMap=new ObjectMap("F:\\Eclipse\\DataFrameWork\\objectMap.properties"); private WebElement element; private WebDriver driver; public HomePage(WebDriver driver){ this.driver=driver; } //返回 首頁 元素對象 public WebElement shouyeText() throws Exception{ //使用objectMap類中的getLocator方法獲取配置文件中關於用戶名的定位方式和定位表達式 element=driver.findElement(objectMap.getLocator("homepage.shouyetext")); return element; } //返回 通訊錄 元素對象 public WebElement tongxunId() throws Exception{ element=driver.findElement(objectMap.getLocator("homepage.addressbook")); return element; } }
在cn.pageObject包下新建LinkmanPage類實現通訊錄頁面各個元素的定位,代碼如下:
package cn.pageObjects; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import cn.util.ObjectMap; public class LinkmanPage { private WebElement element; private WebDriver driver; //指定元素定位表達式配置文件的絕對路徑 private ObjectMap objectMap=new ObjectMap("F:\\Eclipse\\DataFrameWork\\objectMap.properties"); public LinkmanPage(WebDriver driver){ this.driver=driver; } //返回通訊錄頁面中的 新建聯系人 元素 public WebElement addressBook() throws Exception{ element=driver.findElement(objectMap.getLocator("addressbookpage.addlinkman")); return element; } }
在cn.pageObject包下新建AddressBookPage類實現建聯系人界面各個元素的定位,代碼如下:
package cn.pageObjects; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import cn.util.ObjectMap; public class AddressBookPage { private WebElement element; private WebDriver driver; //指定定位元素表達式配置文件的絕對路徑 private ObjectMap objectMap=new ObjectMap("F:\\Eclipse\\DataFrameWork\\objectMap.properties"); public AddressBookPage(WebDriver driver){ this.driver=driver; } //返回新建聯系人界面的 姓名輸入框 public WebElement inputName() throws Exception{ element=driver.findElement(objectMap.getLocator("addressbookpage.name")); return element; } //返回新建聯系人界面的 電子郵箱輸入框 public WebElement inputEmail() throws Exception{ element=driver.findElement(objectMap.getLocator("addressbookpage.email")); return element; } //返回新建聯系人界面的 手機號碼輸入框 public WebElement inputPhonenumber() throws Exception{ element=driver.findElement(objectMap.getLocator("addressbookpage.phonenumber")); return element; } //返回新建聯系人界面的 確定按鈕 public WebElement inputConfirmbutton() throws Exception{ element=driver.findElement(objectMap.getLocator("addressbookpage.confirmbutton")); return element; } }
六、封裝登錄和新建聯系人方法
在cn.appModules包下新建LoginAction類,實現登錄操作的封裝方法
package cn.appModules; //封裝登錄操作 import org.openqa.selenium.WebDriver; import cn.pageObjects.LoginPage; import cn.pageObjects.WaitByElement; import cn.util.WaitMethod; import cn.util.log; public class LoginAction { public static void execute(WebDriver driver,String userName,String passWord) throws Exception{ log.info("瀏覽器最大化"); //瀏覽器最大化 driver.manage().window().maximize(); log.info("實例化LoginPage對象"); //實例化LoginPage對象 LoginPage login=new LoginPage(driver); log.info("點擊進入密碼登錄按鈕"); //點擊進入密碼登錄按鈕 login.intoLogin().click(); log.info("顯示等待"+WaitByElement.loginFrame+" 元素5秒"); //顯示等待 WaitMethod.xsWait(driver,WaitByElement.loginFrame,5); log.info("進入登錄界面的frame"); //控制權交給登錄界面的frame driver.switchTo().frame(login.loginFrame()); log.info("輸入用戶名"+userName); //輸入用戶名 login.userName().sendKeys(userName); log.info("輸入密碼"+passWord); //輸入密碼 login.passWord().sendKeys(passWord); log.info("點擊登錄按鈕"); //點擊登錄按鈕 login.loginButton().click(); // Thread.sleep(5000); } }
在cn.appModules包下新建AddContactPersonAction類,實現新建聯系人操作的封裝方法。代碼如下:
package cn.appModules; import org.openqa.selenium.WebDriver; import cn.pageObjects.AddressBookPage; import cn.pageObjects.HomePage; import cn.pageObjects.LinkmanPage; import cn.pageObjects.WaitByElement; import cn.util.Screenshot; import cn.util.WaitMethod; import cn.util.log; public class AddContactPersonAction { //新建聯系人封裝方法 public static void execute(WebDriver driver,String userName,String passWord, String Name,String Email,String Phonenumber) throws Exception { log.info("調用登錄封裝方法"); //調用登錄封裝方法 try { LoginAction.execute(driver,userName, passWord); } catch (Exception e) { log.info("登錄進入163郵箱首頁失敗"); Screenshot.method(driver,"登錄進入163郵箱首頁失敗"); } log.info("顯示等待"+WaitByElement.weiduButton+" 元素"); //顯示等待 WaitMethod.xsWait(driver,WaitByElement.weiduButton,10); log.info("實例化HomePage對象"); //實例化HomePage對象 HomePage homePage=new HomePage(driver); log.info("點擊 通訊錄"); //點擊 通訊錄 homePage.tongxunId().click(); log.info("顯示等待"+WaitByElement.addLinMan+" 元素"); //顯示等待 WaitMethod.xsWait(driver, WaitByElement.addLinMan, 5); log.info("實例化LinkmanPage對象"); //實例化LinkmanPage對象 LinkmanPage linkmanPage=new LinkmanPage(driver); log.info("點擊 新建聯系人"); //點擊 新建聯系人 linkmanPage.addressBook().click(); log.info("顯示等待"+ WaitByElement.confirmButton+" 元素"); //顯示等待 WaitMethod.xsWait(driver, WaitByElement.confirmButton, 5); log.info("實例化AddressBookPage"); //實例化AddressBookPage AddressBookPage addressbookPage=new AddressBookPage(driver); log.info("輸入聯系人姓名:"+Name); //輸入聯系人姓名 addressbookPage.inputName().sendKeys(Name); log.info("輸入聯系人電子郵箱:"+Email); //輸入聯系人電子郵箱 addressbookPage.inputEmail().sendKeys(Email); log.info("輸入聯系人手機號碼:"+Phonenumber); //輸入聯系人手機號碼 addressbookPage.inputPhonenumber().sendKeys(Phonenumber); log.info("點擊新建聯系人界面的 確定按鈕"); //點擊新建聯系人界面的 確定按鈕 addressbookPage.inputConfirmbutton().click(); } }
七、建立常量類和Excel表格數據
在cn.util包下新建Constant類,代碼如下:
package cn.util; //定義常量 public class Constant { //定義測試網址 public static final String url="https://mail.163.com/"; //定義Excel測試數據文件的路徑 public static final String TestDataExcelFilePath="E:\\Datas\\data.xlsx"; //定義在Excel 文件中包含測試數據的Sheet名稱 public static final String TestDataExcelFileSheet="Sheet1"; }
新建一個Excel表,命名為:data.xlsx ,數據入下圖所示:
用戶名、密碼根據實際情況填寫。注意:手機號這種超長數字類的單元格要設置成文本類型(單元格左上角有個綠三角)
八、測試類。
在cn.testCase包下新建TestEmail163addContactPerson類。代碼如下:
package cn.testCase; import java.io.IOException; import org.apache.log4j.xml.DOMConfigurator; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import cn.appModules.AddContactPersonAction; import cn.util.Constant; import cn.util.ExcelUtil; import cn.util.Screenshot; import cn.util.log; public class TestEmail163addContactPerson { public WebDriver driver; String url=Constant.url; //定義dataprovider,並命名為testData @DataProvider(name="testData") public static Object[][] data() throws IOException{ /* *調用ExcelUtil類中的getTestData靜態方法,獲取Excel數據文件中倒數第二列 *標記為y的測試數據行,函數參數為常量Constant.TestDataExcelFilePath和常量 *Constant.TestDataExcelFileSheet,指定數據文件的路徑和Sheet名稱 */ // System.out.println(Constant.TestDataExcelFilePath); // System.out.println(Constant.TestDataExcelFileSheet); log.info("調用ExcelUtil類中的getTestData靜態方法獲取Excel中標記為y的測試數據"); return ExcelUtil.getTestData(Constant.TestDataExcelFilePath,Constant.TestDataExcelFileSheet); } //使用名稱為testData的dataProvider作為測試方法的測試數據集 //測試方法一個使用了10個參數,對應到Excel數據文件的1~10列 @Test(dataProvider="testData") public void testAddContactPerson(String CaseRow,String CaseName,String UserName, String PassWord,String Name,String Email,String PhoneNumber, String AssertName,String AssertEmail,String AssertPhoneNumber) throws Exception{ log.startTestCase(CaseName); driver.get(url); log.info("訪問網頁"+url); try { log.info("調用AddContactPersonAction類的execute方法"); //調用新建聯系人封裝方法,並傳入相應參數 AddContactPersonAction.execute(driver,UserName, PassWord,Name, Email,PhoneNumber); } catch (Exception e) { /* * 執行AddContactPersonAction類的execute方法失敗時,catch語句可以捕獲AssertionError類型 * 的異常,並設置Excel中測試數據行的執行結果為“測試失敗”。由於Excel中的序號格式被默認設定 * 為帶有一位小數點,所以使用 split("[.]"[0]) 語句獲取序號的整數部分,並傳給setCellData函 * 數在對應序號的測試數據行的最后一列設定“測試失敗” */ ExcelUtil.setCellData(Integer.parseInt(CaseRow.split("[.]")[0]), ExcelUtil.getLastColumnNum(),"測試失敗"); log.info("添加聯系人失敗"); Screenshot.method(driver,"添加聯系人失敗"); log.info("調用Screenshot.method方法進行截圖"); log.endTestCase(CaseName); //調用Assert.fail方法將此測試用例設定為執行失敗,后續測試代碼將不被執行 Assert.fail("執行AddContactPersonAction類的execute方法失敗"); } Thread.sleep(3000); log.info("調用AddContactPersonAction類的execute方法后休眠3秒"); try{ log.info("斷言頁面是否包含聯系人姓名:"+AssertName); //斷言頁面是否包含AssertName變量的關鍵字 Assert.assertTrue(driver.getPageSource().contains(AssertName)); }catch(AssertionError error){ log.info("斷言通訊錄頁面是否包含聯系人姓名:"+AssertName +" 失敗"); ExcelUtil.setCellData(Integer.parseInt(CaseRow.split("[.]")[0]), ExcelUtil.getLastColumnNum(),"測試失敗"); Screenshot.method(driver, "斷言聯系人姓名為"+AssertName+"失敗"); log.info("調用Screenshot.method方法進行截圖"); log.endTestCase(CaseName); Assert.fail("斷言通訊錄頁面是否包含聯系人姓名的關鍵字失敗"); } try{ log.info("斷言頁面是否包含聯系人郵箱:"+AssertEmail); //斷言頁面是否包含AssertEmail變量的關鍵字 Assert.assertTrue(driver.getPageSource().contains(AssertEmail)); }catch(AssertionError error){ log.info("斷言通訊錄頁面是否包含聯系人郵箱地址:"+AssertEmail+" 失敗"); ExcelUtil.setCellData(Integer.parseInt(CaseRow.split("[.]")[0]), ExcelUtil.getLastColumnNum(),"測試失敗"); log.info("調用Screenshot.method方法進行截圖"); Screenshot.method(driver,"斷言聯系人郵箱為"+AssertEmail+"失敗"); log.endTestCase(CaseName); Assert.fail("斷言通訊錄頁面是否包含聯系人郵箱地址的關鍵字失敗"); } try{ log.info("斷言通訊錄頁面是否包含聯系人手機號碼:"+AssertPhoneNumber); //斷言頁面是否包含AssertPhoneNumber變量的關鍵字 Assert.assertTrue(driver.getPageSource().contains(AssertPhoneNumber)); }catch(AssertionError error){ ExcelUtil.setCellData(Integer.parseInt(CaseRow.split("[.]")[0]), ExcelUtil.getLastColumnNum(),"測試失敗"); log.info("斷言通訊錄頁面是否包含聯系人手機號碼:"+AssertPhoneNumber+" 失敗"); Screenshot.method(driver,"斷言聯系人手機號碼為"+AssertPhoneNumber+"失敗"); log.info("調用Screenshot.method方法進行截圖"); log.endTestCase(CaseName); Assert.fail("斷言通訊錄頁面是否包含聯系人手機號碼關鍵字失敗"); } ExcelUtil.setCellData(Integer.parseInt(CaseRow.split("[.]")[0]), ExcelUtil.getLastColumnNum(),"測試成功"); log.info("新建聯系人全部斷言成功,在Excel的測試數據文件“測試執行結果”列中寫入“測試成功”"); log.endTestCase(CaseName); } @BeforeClass public void beforeClass() throws Exception{ //讀取Log4j.xml配置文件信息 DOMConfigurator.configure("Log4j.xml"); //使用Constant類中的常量,設定測試數據的文件路徑和Sheet名稱 ExcelUtil.setExcelFile(Constant.TestDataExcelFilePath,Constant.TestDataExcelFileSheet); log.info("使用Constant類中的常量,設定測試數據的文件路徑:"+Constant.TestDataExcelFilePath); log.info("使用Constant類中的常量,設定測試數據的Sheet名稱:"+Constant.TestDataExcelFileSheet); } @BeforeMethod public void beforeMethod(){ System.setProperty("webdriver.chrome.driver","E://chromedriver.exe"); driver=new ChromeDriver(); log.info("啟動瀏覽器"); } @AfterMethod public void afterMethod(){ driver.quit(); log.info("關閉瀏覽器"); } }
運行TestEmail163addContactPerson測試類后,結果如下幾圖所示:
testng運行結果:
log4j打印日志:
錯誤截圖:
Excel表格用例執行結果列自動寫入結果:
如果有錯誤或不足之處,歡迎指正(^∀^)