Selenium Web Driver自動化測試(java版)系列下半部分(31) - 用數據驅動搭建測試框架雛形(4) - 添加測試配置文件以及利用java反射機制優化控制類

上篇我們添加了用戶模塊的test case,算上登錄模塊,我們已經有五個test case了。TestRunner.java看起來如下:

可以看出來,隨著TestRunner.java越來越長,如果有很多test case你就得實例化每一個+調用test()方法,很不方便維護。比如我現在只想執行登錄模塊的,不想執行別的?或者是,現在的系統默認是用chrome來跑的,我想用ie或是firefox該怎么辦呢?其中一個答案就是設置一個配置文件來解決。通過讀取文件上的值我們可以自由配置我們想要的測試參數,如果希望改變則直接修改配置文件即可。

首先聲明一下,配置文件可以是任意格式、任意后綴名的,只要滿足你設計的框架要求就行了。我們設計框架以來一直用的都是Excel文件,那這次搞配置文件我們就用csv文件吧,順便復習一下。新建文件夾config -> config.csv:

在里面寫上如下內容:

就這一行,里面有4列,定義了用哪種瀏覽器,driver的路徑,以及測試的模塊等:

先把csv文件上的數據讀到數組里,文件讀取也屬于測試中的一些常用的、必要的步驟,所以還是放在com.testalliance.hrsystem.test中,這里我們創建一個新類Utility.java:

寫如下代碼:

依靠getModules()方法讀取csv文件的內容,讀到逗號時進行分割并把當前一行信息放入一個數組中,然后把每一個數組放入ArrayList里。不太理解的朋友可以去參考csv文件操作那篇。接下來我們把TestRunner.java改成下面這個樣子:

第16行調用getModules()方法獲取所有的配置信息,然后通過循環ArrayList一個個讀取出來。第27行和28行是處理測試模塊的步驟,可能有些人看不太懂。第27行用字符串的replace()方法將"{"和"}"去掉,然后以“|”為新的分隔符再劃分成幾部分放入arr_modules數組中。比如我們例子中從ArrayList讀取出來的最后一列字符串是"{login|employee}",先將左右括號去掉后變成"login|employee",再以"|"為分隔符把login和employee放進數組arr_modules里。另外,你可以把每個case的test()方法都修改成接受三個參數用于執行測試步驟。這么一改,我發現可以有選擇性地執行模塊了。

但即便是這樣,我們還是覺得TestRunner.java很臃腫,測試用例多了之后還要加上各種判斷語句和實例化過程,其實并沒有改變太多。所以,我們還要繼續修改。首先觀察一下測試用例類和測試文件的名稱:

文件名稱是一一對應的,只不過后綴名不一樣而已。仔細想一下,如果只希望執行某個模塊的測試用例,我們勢必要遍歷整個測試文件夾:

每讀到一個文件,就要實例化對應的用例,比如讀到TCLogin3.xlsx,我們就要實例化TCLogin3,讀到TCEmp1.xlsx,我們就要實例化TCEmp1。測試文件名本質上是一個字符串,而類名本質上是一個類,那我可不可以有一種辦法,可以把字符串轉成類,這樣是不是程序執行時只要通過循環讀取文件名就能自動實例化類了?是不是我們就不用再一遍遍來回寫了?做這步之前,我們先簡單修改一下TestRunner.java:

畫紅框的部分就是增加或修改的地方,第30行到37行就是遍歷某個測試數據文件夾然后取出某個文件名的過程。取出的文件名帶有后綴.xlsx,要去掉,因為類名是沒有后綴的。這里用到的都是字符串的操作,不說太多了。正是因為我們每次取出一個文件代表一個類,也就是一個測試用例,我們其實可以把測試的準備工作從每個test()方法中單獨提取出來,這步在第45行和46行。因為單獨提取出來了,那我們完全可以在準備步驟里就傳入driverBrowser,driverPath和browser三個參數,test()方法里只需要傳入driver即可。這樣,準備工作是準備工作,測試步驟是測試步驟,兩者分開了。把測試類中test()方法里的準備步驟去掉,以TCLogin1.java為例:

現在更明顯了吧?我們現在要做的就是要把TestRunner.java里面的if-else語句替換成文件名轉類名的過程就行了。好了,問題來了,怎樣才能把文件名轉成類名呢?java里有一個類似的功能,叫做反射機制,可以幫助我們。

首先我們回顧一下之前介紹的一些java基本概念。在討論面向對象的時候我們說實例化一個對象時內存中應該是這樣的:

當執行到Wanghong w = new Wanghong()時,Wanghong對象被創建出來,但與此同時其實還有一個對象被創建出來(其實是在.class文件被加載到JVM的時候),這個對象的類型是Class,指向的是Wanghong類的一些信息:

我們在介紹java的第一篇就說了,一段程序運行時首先會生成一個.class文件,隨后這個.class文件會被加載到java虛擬機(JVM)中并被執行,這個Class類型的對象就是這個時候創建的。那怎樣得到這個對象呢?為了演示,我新建了一個叫JavaReflection的項目:

看下面的代碼:

Wanghong.java:

Test.java:

看Test.java,第一種得到Class類對象的方法就是用Wanghong類的對象調用一個叫getClass()的方法,然后可以打印出來它的一些基本信息;第二種方法直接調用class屬性;第三種調用forName()方法,需要添加該類的完整路徑作為參數,注意是完整路徑,包括包名。

有一點需要指出的是,在同一個運行時一個類只有一個Class類對象被創建出來,也就是說wClass1、wClass2、wClass3它們都是一個東西。Java反射這部分知識在測試中暫時用得不多,我就講到這兒,具體可以參考其它一些文章,我參考的就是這篇,講得很詳細。大家現在仔細看看第三種方式,類的完整路徑是一個字符串,我們通過這個字符串可以獲得類名。有人說你講這個反射我還是沒明白和咱們的測試執行有什么關系,接著看。java映射的概念就是可以把一個類中的成員(包,構造方法,成員方法,成員變量等等)映射成一個個對象,比如Class對象,是通過com.test包中的Wanghong類得到的。同樣,如果我們寫Class c = Class.forName("com.testalliance.hrsystem.tests.login.TCLogin1“)也會得到一個Class對象。TCLogin1.java里有一個test()方法,用于執行測試用例,我們也可以把這個成員方法映射成對象。TCLogin1.java默認還有構造函數,用于初始化一個對象,我們還可以把構造函數映射成對象。這么多對象干什么用?答案在下面的紅框里:

第59行是成員方法的反射使用。用Class對象調用getMethod()方法可以獲取到某個成員方法的對象,它接收的參數一個是方法名,還一個是參數類型,因為我們是driver,所以寫WebDriver.class。參數類型根據方法的參數個數而定,test()方法只有一個driver參數,所以我們只放一個WebDriver.class。第61行是構造方法的反射使用,構造方法的作用是初始化一個類,在這里會得到測試類的對象classObj,這一步相當于Wanghong w = new Wanghong()。第63行用方法對象調用invoke方法傳入classObj和driver作為參數,相當于調用了test()方法。其實還是一個道理,只不過對象、方法、參數都顛倒過來了,感覺很別扭。這種正向反向可以看下圖對比一下:

想初始化測試類就得先獲取Class對象,想調用test()方法就得先獲取方法對象,這么理解可能就容易些。更多反射的用法還是可以參照這篇,我就不再啰嗦了。

執行一下,測試通過。改動到此為止,下一篇我們再做幾個簡單的變化,這個框架雛形就完成了。對于配置文件來說還是那句話,只要和自己設計的框架吻合就可以了。

這篇文章的源代碼在SeleniumExcelDataDrivenFrame4項目里邊。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,754評論 18 399
  • 上兩篇我們結合數據驅動討論了page object模型,分別用了Excel和csv進行演示。其中Excel參與的演...
    馬可吃菠蘿閱讀 743評論 0 2
  • 屋頂不高。瓦片灰塵掉落在地板上,像一朵朵雪白的云絮沒有一絲風堆在一起。淡淡的陽光在玻璃窗縫射進來。辛而緊接對著她的...
    兔m閱讀 337評論 0 0
  • 防皺養顏:山藥燴秋葵 主料:山藥180克,胡蘿卜180克,黃秋葵120克,玉米筍120克,大棗30克。 配料:油3...
    89不離食閱讀 366評論 0 0
  • 想研究美圖的初衷在于其做為廈門目前最知名的互聯網公司之神秘(身為廈門人的我更為好奇)。 而且這2年其動作之頻繁: ...
    ElekChen閱讀 496評論 4 2