上篇我們添加了用戶模塊的test case锨侯,算上登錄模塊逼裆,我們已經(jīng)有五個test case了睛驳。TestRunner.java看起來如下:
可以看出來凰浮,隨著TestRunner.java越來越長,如果有很多test case你就得實例化每一個+調(diào)用test()方法拙已,很不方便維護决记。比如我現(xiàn)在只想執(zhí)行登錄模塊的,不想執(zhí)行別的倍踪?或者是系宫,現(xiàn)在的系統(tǒng)默認是用chrome來跑的,我想用ie或是firefox該怎么辦呢建车?其中一個答案就是設(shè)置一個配置文件來解決扩借。通過讀取文件上的值我們可以自由配置我們想要的測試參數(shù),如果希望改變則直接修改配置文件即可缤至。
首先聲明一下潮罪,配置文件可以是任意格式、任意后綴名的,只要滿足你設(shè)計的框架要求就行了嫉到。我們設(shè)計框架以來一直用的都是Excel文件沃暗,那這次搞配置文件我們就用csv文件吧,順便復習一下何恶。新建文件夾config -> config.csv:
在里面寫上如下內(nèi)容:
就這一行孽锥,里面有4列,定義了用哪種瀏覽器细层,driver的路徑惜辑,以及測試的模塊等:
先把csv文件上的數(shù)據(jù)讀到數(shù)組里,文件讀取也屬于測試中的一些常用的疫赎、必要的步驟盛撑,所以還是放在com.testalliance.hrsystem.test中,這里我們創(chuàng)建一個新類Utility.java:
寫如下代碼:
依靠getModules()方法讀取csv文件的內(nèi)容虚缎,讀到逗號時進行分割并把當前一行信息放入一個數(shù)組中撵彻,然后把每一個數(shù)組放入ArrayList里。不太理解的朋友可以去參考csv文件操作那篇实牡。接下來我們把TestRunner.java改成下面這個樣子:
第16行調(diào)用getModules()方法獲取所有的配置信息陌僵,然后通過循環(huán)ArrayList一個個讀取出來。第27行和28行是處理測試模塊的步驟创坞,可能有些人看不太懂碗短。第27行用字符串的replace()方法將"{"和"}"去掉,然后以“|”為新的分隔符再劃分成幾部分放入arr_modules數(shù)組中题涨。比如我們例子中從ArrayList讀取出來的最后一列字符串是"{login|employee}"偎谁,先將左右括號去掉后變成"login|employee",再以"|"為分隔符把login和employee放進數(shù)組arr_modules里纲堵。另外巡雨,你可以把每個case的test()方法都修改成接受三個參數(shù)用于執(zhí)行測試步驟。這么一改席函,我發(fā)現(xiàn)可以有選擇性地執(zhí)行模塊了铐望。
但即便是這樣,我們還是覺得TestRunner.java很臃腫茂附,測試用例多了之后還要加上各種判斷語句和實例化過程正蛙,其實并沒有改變太多。所以营曼,我們還要繼續(xù)修改乒验。首先觀察一下測試用例類和測試文件的名稱:
文件名稱是一一對應的,只不過后綴名不一樣而已蒂阱。仔細想一下锻全,如果只希望執(zhí)行某個模塊的測試用例狂塘,我們勢必要遍歷整個測試文件夾:
每讀到一個文件,就要實例化對應的用例鳄厌,比如讀到TCLogin3.xlsx睹耐,我們就要實例化TCLogin3,讀到TCEmp1.xlsx部翘,我們就要實例化TCEmp1。測試文件名本質(zhì)上是一個字符串响委,而類名本質(zhì)上是一個類新思,那我可不可以有一種辦法,可以把字符串轉(zhuǎn)成類赘风,這樣是不是程序執(zhí)行時只要通過循環(huán)讀取文件名就能自動實例化類了夹囚?是不是我們就不用再一遍遍來回寫了?做這步之前邀窃,我們先簡單修改一下TestRunner.java:
畫紅框的部分就是增加或修改的地方荸哟,第30行到37行就是遍歷某個測試數(shù)據(jù)文件夾然后取出某個文件名的過程。取出的文件名帶有后綴.xlsx瞬捕,要去掉鞍历,因為類名是沒有后綴的。這里用到的都是字符串的操作肪虎,不說太多了劣砍。正是因為我們每次取出一個文件代表一個類,也就是一個測試用例扇救,我們其實可以把測試的準備工作從每個test()方法中單獨提取出來刑枝,這步在第45行和46行。因為單獨提取出來了迅腔,那我們完全可以在準備步驟里就傳入driverBrowser装畅,driverPath和browser三個參數(shù),test()方法里只需要傳入driver即可沧烈。這樣掠兄,準備工作是準備工作,測試步驟是測試步驟掺出,兩者分開了徽千。把測試類中test()方法里的準備步驟去掉,以TCLogin1.java為例:
現(xiàn)在更明顯了吧汤锨?我們現(xiàn)在要做的就是要把TestRunner.java里面的if-else語句替換成文件名轉(zhuǎn)類名的過程就行了双抽。好了,問題來了闲礼,怎樣才能把文件名轉(zhuǎn)成類名呢牍汹?java里有一個類似的功能铐维,叫做反射機制,可以幫助我們慎菲。
首先我們回顧一下之前介紹的一些java基本概念嫁蛇。在討論面向?qū)ο蟮臅r候我們說實例化一個對象時內(nèi)存中應該是這樣的:
當執(zhí)行到Wanghong w = new Wanghong()時,Wanghong對象被創(chuàng)建出來露该,但與此同時其實還有一個對象被創(chuàng)建出來(其實是在.class文件被加載到JVM的時候)睬棚,這個對象的類型是Class,指向的是Wanghong類的一些信息:
我們在介紹java的第一篇就說了解幼,一段程序運行時首先會生成一個.class文件抑党,隨后這個.class文件會被加載到java虛擬機(JVM)中并被執(zhí)行,這個Class類型的對象就是這個時候創(chuàng)建的撵摆。那怎樣得到這個對象呢底靠?為了演示,我新建了一個叫JavaReflection的項目:
看下面的代碼:
Wanghong.java:
Test.java:
看Test.java特铝,第一種得到Class類對象的方法就是用Wanghong類的對象調(diào)用一個叫g(shù)etClass()的方法暑中,然后可以打印出來它的一些基本信息;第二種方法直接調(diào)用class屬性鲫剿;第三種調(diào)用forName()方法鳄逾,需要添加該類的完整路徑作為參數(shù),注意是完整路徑牵素,包括包名严衬。
有一點需要指出的是,在同一個運行時一個類只有一個Class類對象被創(chuàng)建出來笆呆,也就是說wClass1请琳、wClass2、wClass3它們都是一個東西赠幕。Java反射這部分知識在測試中暫時用得不多俄精,我就講到這兒,具體可以參考其它一些文章榕堰,我參考的就是這篇竖慧,講得很詳細。大家現(xiàn)在仔細看看第三種方式逆屡,類的完整路徑是一個字符串圾旨,我們通過這個字符串可以獲得類名。有人說你講這個反射我還是沒明白和咱們的測試執(zhí)行有什么關(guān)系魏蔗,接著看砍的。java映射的概念就是可以把一個類中的成員(包,構(gòu)造方法莺治,成員方法廓鞠,成員變量等等)映射成一個個對象帚稠,比如Class對象,是通過com.test包中的Wanghong類得到的床佳。同樣滋早,如果我們寫Class c = Class.forName("com.testalliance.hrsystem.tests.login.TCLogin1“)也會得到一個Class對象。TCLogin1.java里有一個test()方法砌们,用于執(zhí)行測試用例杆麸,我們也可以把這個成員方法映射成對象。TCLogin1.java默認還有構(gòu)造函數(shù)浪感,用于初始化一個對象角溃,我們還可以把構(gòu)造函數(shù)映射成對象。這么多對象干什么用篮撑?答案在下面的紅框里:
第59行是成員方法的反射使用。用Class對象調(diào)用getMethod()方法可以獲取到某個成員方法的對象匆瓜,它接收的參數(shù)一個是方法名赢笨,還一個是參數(shù)類型,因為我們是driver驮吱,所以寫WebDriver.class茧妒。參數(shù)類型根據(jù)方法的參數(shù)個數(shù)而定,test()方法只有一個driver參數(shù)左冬,所以我們只放一個WebDriver.class桐筏。第61行是構(gòu)造方法的反射使用,構(gòu)造方法的作用是初始化一個類拇砰,在這里會得到測試類的對象classObj梅忌,這一步相當于Wanghong w = new Wanghong()。第63行用方法對象調(diào)用invoke方法傳入classObj和driver作為參數(shù)除破,相當于調(diào)用了test()方法牧氮。其實還是一個道理,只不過對象瑰枫、方法踱葛、參數(shù)都顛倒過來了,感覺很別扭光坝。這種正向反向可以看下圖對比一下:
想初始化測試類就得先獲取Class對象尸诽,想調(diào)用test()方法就得先獲取方法對象,這么理解可能就容易些盯另。更多反射的用法還是可以參照這篇性含,我就不再啰嗦了。
執(zhí)行一下土铺,測試通過胶滋。改動到此為止板鬓,下一篇我們再做幾個簡單的變化,這個框架雛形就完成了究恤。對于配置文件來說還是那句話俭令,只要和自己設(shè)計的框架吻合就可以了。
這篇文章的源代碼在SeleniumExcelDataDrivenFrame4項目里邊部宿。