因爲公司的開發團隊偏向於使用Java技術,並且公司倡導學習開源技術,因此我選擇用Java語言來進行Selenium WebDriver的自動化框架開發。因爲本人沒有Java開發經驗,之前雖然學過QTP但從沒有接觸過Selenium,正好經過這個機會能學習一下自動化測試,同時也學習一下基本的Java開發過程。html
1、首先是搭建框架開發環境java
按照網上的方法部署eclipse,創建TestAction工程,並Import引用JDK和Selenium-2.44完整包c++
2、繼續引用和安裝相關jar包web
一、首先是要知足數據驅動(場景用例和動做用例、數據用例都須要放到excel表上),就須要引用jxl.rar包(實現調用和操做excel);chrome
二、須要實現自動化框架(有測試套件、測試層)就須要經過eclipse安裝TestNg(網上有相關教程);express
3、構建框架的樣例代碼apache
一、實現可以對excel用例數據的調用(經過jxl的引用),建立ExcelData.java類文件(專門用於對excel的調用),如下截取部分代碼樣例:數組
/** * @param fileName excel文件名 * @param caseName sheet名 */ public ExcelData(String fileName, String caseName) { super(); this.fileName = fileName; this.caseName = caseName; } /** * 得到excel表中的數據 */ public Object[][] getExcelData() throws BiffException, IOException { workbook = Workbook.getWorkbook(new File(getPath())); sheet = workbook.getSheet(caseName); rows = sheet.getRows(); columns = sheet.getColumns(); // 爲了返回值是Object[][],定義一個多行單列的二維數組 @SuppressWarnings("unchecked") HashMap<String, String>[][] arrmap = new HashMap[rows - 1][1]; // 對數組中全部元素hashmap進行初始化 if (rows > 1) { for (int i = 0; i < rows - 1; i++) { arrmap[i][0] = new HashMap<String, String>(); } } else { System.out.println("excel中沒有數據"); } // 得到首行的列名,做爲hashmap的key值 for (int c = 0; c < columns; c++) { String cellvalue = sheet.getCell(c, 0).getContents(); arrkey.add(cellvalue); } // 遍歷全部的單元格的值添加到hashmap中 for (int r = 1; r < rows; r++) { for (int c = 0; c < columns; c++) { String cellvalue = sheet.getCell(c, r).getContents(); arrmap[r - 1][0].put(arrkey.get(c), cellvalue); } } return arrmap; } /** * 得到excel文件的路徑 * @return * @throws IOException */ public String getPath() throws IOException { File directory = new File("."); sourceFile = directory.getCanonicalPath() + "\\src\\source\\" + fileName + ".xls"; return sourceFile; }
二、實現對瀏覽器的調用,考慮到兼容性,須要同時知足對Chrome、FireFox、IE三大瀏覽器的調用,咱們須要準備相關驅動chromedriver.exe、IEDriverServer.exe,這兩驅動都是谷歌和IE官方提供的,能夠從網上下載到;而FireFox不須要下載驅動,只要安裝瀏覽器就可調用(Selenium和FireFox屬於一個團隊開發出來的,待遇就是不同)。瀏覽器
有了瀏覽器驅動後(咱們把驅動放到工程目錄的WebDriver文件夾下,方便按相對路徑統一調用),咱們就須要一個能調用瀏覽器的類,如下提供核心代碼樣例:安全
public static WebDriver getChromeDriver(String url) { //加載Google驅動 //System.setProperty("webdriver.chrome.driver","D:\\java\\chromedriver.exe"); System.setProperty("webdriver.chrome.driver",System.getProperties().getProperty("user.dir")+"\\WebDriver\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); //經過配置參數禁止data;的出現 options.addArguments("--user-data-dir="+System.getProperties().getProperty("user.home")+"/AppData/Local/Google/Chrome/User Data/Default"); //經過配置參數刪除「您使用的是不受支持的命令行標記:--ignore-certificate-errors。穩定性和安全性會有所降低。」提示 options.addArguments("--start-maximized","allow-running-insecure-content", "--test-type"); WebDriver driver = new ChromeDriver(options); driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); driver.navigate().to(url); return driver; } public static WebDriver getFireFoxDriver(String url){ System.setProperty("webdriver.firefox.bin", "D:\\Program Files\\Mozilla Firefox\\firefox.exe"); // TODO Auto-generated method stub WebDriver driver = new FirefoxDriver(); //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(url); return driver; } public static WebDriver getIEDriver(String url){ //System.setProperty("webdriver.ie.driver", "D:\\java\\IE64\\IEDriverServer.exe"); System.setProperty("webdriver.ie.driver", System.getProperties().getProperty("user.dir")+"\\WebDriver\\IE32\\IEDriverServer.exe"); DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer(); capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,true); capabilities.setPlatform(Platform.WINDOWS); capabilities.setCapability("silent", true); // TODO Auto-generated method stub WebDriver driver = new InternetExplorerDriver(capabilities); //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(url); return driver; }
三、寫一個以數據驅動的場景類,來進行單個事務的用例跑測
(1)首行咱們須要用TesgNg提供的數據驅動方法(@DataProvider),來獲取一個場景的用例表數據,這個場景從excel的第一個附表獲取
經過action名,調取用例表(用例表是以action名命名的附表),用例表以下所示(ExpectedObject表示用例校驗對象的頁面Element標籤,用;分隔,分號前面的表示ID,分號後面的表示xpath):
如下爲用例表數據獲取的代碼:
@DataProvider(name="action") public Object[][] Numbers() throws BiffException, IOException{ getActionString = actionData.getActionStr(1);//獲取第一個場景的broswer、url、action名 ExcelData e=new ExcelData("testdata", getActionString.get(2)); return e.getExcelData(); }
而後經過Java的反射機制,實現動態的獲取具體事務類和執行相關操做(每一個事務的類名和方法名都與action場景名一致),如下截選相關場景的部分調用代碼:
@Test(dataProvider="action") public void testAction(HashMap<String, String> data) throws BiffException, IOException { try { Class<?> MyClass = Class.forName(packageName+"."+getActionString.get(2)); Method method = MyClass.getMethod(getActionString.get(2),WebDriver.class); @SuppressWarnings("unused") String [] results = (String []) method.invoke(,driver); String ExpObject=data.get("ExpectedObject"); String ExpObject_by=ExpObject.split(";")[0].toString(); String ExpObject_Desc=ExpObject.split(";")[1].toString(); if(ExpObject_by.length()>0){ Assert.assertEquals(driver.findElement(By.id(ExpObject_by)).getText(),data.get("ExpectedData"), getActionString.get(2)+data.get("ID")+"驗證結果:"); } else if(ExpObject_Desc.length()>0){ Assert.assertEquals(driver.findElement(By.xpath(ExpObject_Desc)).getText(),data.get("ExpectedData"), getActionString.get(2)+data.get("ID")+"驗證結果:"); } WebDriverDemo.WebSleep(500); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
另外說明的是,調用瀏覽器的方法,須要明確是放在@BeforeMethod中,仍是在@BeforeClass中,若是是登陸校驗測試,就要保證每次執行測試方法都要打開一次瀏覽器和關閉一次瀏覽器,那麼咱們就要把調用瀏覽器,和關閉瀏覽器的方法放到@BeforeMethod中和@AfterMethod中。其餘業務測試,只要在一個套件類中打開一次瀏覽器和關閉一次瀏覽器就能夠,因此用到的是@BeforeClass和@AfterClass。
四、咱們須要再寫一個以動做(關鍵詞)驅動的場景類
一樣,調用第二個場景的用例表,樣例代碼以下:
@DataProvider(name="action") public Object[][] Numbers() throws BiffException, IOException{ getActionString = actionData.getActionStr(2);//獲取第二個場景的broswer、url、action名 ExcelData e=new ExcelData("testdata", getActionString.get(2)); return e.getExcelData(); }
而後在測試方法中,動態的調用具體操做動做,獲取WebElement標籤的方法,包括經過By ID或者By xpath,操做動做以最多見的兩個爲例(sendKeys、click),如下爲樣例代碼節選:
@Test(dataProvider="action") public void testAction(HashMap<String, String> data) throws BiffException, IOException { //driver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS);//找不到element就再給5秒查找 try { WebElement TestWebElement = ; String SetObject=data.get("SetObject").trim(); String SetObject_by=SetObject.split(";")[0].toString(); String SetObject_Desc=SetObject.split(";")[1].toString(); if(SetObject_by.length()>0){ TestWebElement=driver.findElement(By.id(SetObject_by)); } else if(SetObject_Desc.length()>0){ TestWebElement=driver.findElement(By.xpath(SetObject_Desc)); } if(data.get("SetOperate").equals("sendKeys")){ TestWebElement.clear(); TestWebElement.sendKeys(data.get("SetValue")); }else if(data.get("SetOperate").equals("click")){ TestWebElement.click(); } String ExpObject=data.get("ExpectedObject").trim(); if(ExpObject.length()>0){ String ExpObject_by=ExpObject.split(";")[0].toString(); String ExpObject_Desc=ExpObject.split(";")[1].toString(); if(ExpObject_by.length()>0){ Assert.assertEquals(driver.findElement(By.id(ExpObject_by)).getText(),data.get("ExpectedData"), getActionString.get(2)+data.get("ID")+"驗證結果:"); } else if(ExpObject_Desc.length()>0){ Assert.assertEquals(driver.findElement(By.xpath(ExpObject_Desc)).getText(),data.get("ExpectedData"), getActionString.get(2)+data.get("ID")+"驗證結果:"); } } WebDriverDemo.WebSleep(500); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
這段方法所調用的用例表以下所示(以登陸爲例):
五、剩下就是業務擴展類了,全部複雜的事務均可以單獨創建測試類和方法(方便擴展維護,只須要在excel場景表中定義後就能調用,利用的是Java反射機制),在這裏就不舉例了。
4、實現測試套件調用和報告輸出
有了以上步驟,一個可擴展的自動化框架已經基本造成,可是還達不到大規模應用測試和腳本方即可移植,這時候咱們引入Ant(能夠在Eclipse中安裝插件,能夠直接上網下載後引用),爲了能輸出漂亮一點的報告格式,咱們還引入一個saxon-8.7.jar。
有了Ant後,咱們就能夠建議build.xml文件,就能一鍵bulid咱們以上的自動化代碼,並將執行測試後的結果輸出成報告。
一、首先咱們須要編輯好測試套件調用的testng.xml,簡單舉例以下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite" parallel="false"> <test verbose="2" name="Test_Action"> <!--<groups> <run> <include name="aaa" /> <include name="bbb" /> <include name="ccc" /> </run> </groups>--> <classes> <class name="TestBrowser.ExcActions"/> <class name="TestBrowser.ExcActions2"/> </classes> </test> <!-- Default test --> </suite> <!-- Default suite -->
二、而後咱們須要編輯好一個能引用基礎jar包、build測試代碼、調用testng、輸出漂亮報告的build.xml文件
<?xml version="1.0" encoding="UTF-8"?> <project name= "TestAction" basedir= "." default="testoutput"><!--default設置爲run表示只執行腳本,設爲testoutput表示執行完腳本並輸出視圖報告--> <echo message="import libs" /> <property name= "lib.dir" value= "lib" /> <!--<property name="libdir" location="${basedir}/lib" />--> <!--<property name="testng.output.dir" location="${basedir}/test-output" />--> <path id= "test.classpath" > <!-- adding the saxon jar to your classpath --> <fileset dir= "${lib.dir}" includes= "*.jar" /> <fileset dir="${basedir}/selenium-2.44.0"> <include name="selenium-java-2.44.0.jar" /> <include name="libs/*.jar" /> </fileset> </path> <taskdef name="testng" classname="org.testng.TestNGAntTask" classpathref="test.classpath" /> <target name="clean"> <delete dir="build"/> </target> <target name="compile" depends="clean"> <echo message="mkdir"/> <mkdir dir="build/classes"/> <javac srcdir="src" destdir="build/classes" debug="on" encoding="UTF-8" includeAntRuntime="false"> <classpath refid="test.classpath"/> </javac> </target> <path id="runpath"> <path refid="test.classpath"/> <pathelement location="build/classes"/> </path> <target name="run" depends="compile"> <testng classpathref="runpath" outputDir="test-output"> <xmlfileset dir="${basedir}" includes="testng.xml"/> <jvmarg value="-ea" /> </testng> </target> <target name= "testoutput" depends="run"> <xslt in= "test-output/testng-results.xml" style= "test-output/testng-results.xsl" out= "test-output/index1.html" > <!-- you need to specify the directory here again --> <param name= "testNgXslt.outputDir" expression= "${basedir}/test-output/" /> <param name="testNgXslt.showRuntimeTotals" expression="true" /> <classpath refid= "test.classpath" /> </xslt> </target> </project>
三、完成這些後,咱們就能夠經過Eclipse直接Run As Ant Build咱們的自動化腳本了,輸出一份還算漂亮的報告:
同時,須要在事務操做類中,對實際結果和預期結果進行比較,並將測試結果寫入excel的用例表中,以下:
String[] result=new String [2]; result[0] = driver.findElement(By.xpath(pars.get(3).split(";")[1].toString())).getText(); result[1] = pars.get(4); if(result[0].equals(result[1])){//pars.size()-1 ActionsDemo.modifyExcel(Thread.currentThread().getStackTrace()[1].getMethodName(),k,5,"經過"); } else { ActionsDemo.modifyExcel(Thread.currentThread().getStackTrace()[1].getMethodName(),k,5,"失敗"); }
5、實現自動化框架腳本的遷移調用
以上的腳本始終是在Eclipse下編譯和調用的,若是要實現靈活遷移,隨便換任何一臺只裝了JDK的電腦都能運行,那麼咱們就要來點改造
一、首行是保證咱們寫的代碼中,因此須要引用文件的地方,都用相對路徑的方式,避免代碼包遷移後須要改路徑。
二、經過批處理調用build文件及用例文件,調用時也是經過批處理自動找到相關路徑,避免用絕對路徑。
三、須要用環境變量的地方,儘可能用批處理的方式實現,甚至最好是不用配置環境變量,直接調用相引用相對命令文件的路徑調用
如下舉個經過bat批處理調用Ant來執行整個框架代碼的build:
@echo off ::先將測試用例文件拷到用戶目錄下 copy src\source\testdata.xls %UserProfile%\src\source %cd%\org.apache.ant_1.9.6\bin\ant.bat -buildfile build.xml echo 在%cd%\test-output下查看測試報告 pause
6、進一步實現自動化的持續集成
在以上基礎上,咱們還能夠經過jenkins實現對自動化腳本的調用,以及達到每日構建,持續集成開發的要求。
一、首先部署jenkins(網上有相關方法),因爲本人公司一直在用jenkins,我就省了搭建部署這一步,直接將以上的自動化框架腳本上傳
二、自動化腳本完整目錄(包括代碼、用例、lib、引用的jar、build.xml文件等)上傳到SVN(再自動從SVN下到jenkins所在服務器)
三、在jenkins中新建一個測試項目TestAction,主要配置以下:
四、配置完後,就能夠當即構建(若是碰到相關報錯問題,就按輸出的提示進行處理),構建成功後,就能夠在HTML_Report中看到測試結果:
7、後續處理
到此爲止,一個完整的Selenium自動化框架就出來了,要說好用不,很差說,還得通過實踐的檢驗,可是以上這個思考過程和框架的演進過程,應該也是值得借鑑的,畢竟這是我這幾天摸索和學習的過程,對於一個沒有從事過自動化測試,並且沒有作過Java開發的測試人員來講,這只是個開始。
目前來看,這個框架在架構分層上,仍是不夠清晰,有不少要改進的東西,從技術上來講,我已經實現了個人目標(學習自動化測試),可是在總體架構和代碼重構上,還有不少工做沒作,如下貼出一份Selenium自動化框架的分層結構,以便後期按照這個標準進行改進:
測試數據層:獨立封裝數據;
頁面對象層:封裝頁面對象,共頁面任務層作調用;
頁面任務層:實現各個獨立頁面的操做;
測試層:實現頁面測試;
測試套件層:實現測試層的管理調用;
跟你們推薦一個學習資料分享羣:747981058,裏面大牛已經爲咱們整理好了許多的學習資料,有自動化,接口,性能等等的學習資料!人生是一個逆水行舟的過程,不進則退,我們一塊兒加油吧!