Selenium 如何快速搭建 Web 自動化測試框架

一、寫在前面的話

在使用WebDriver框架之前,我先后使用了其他兩款自動化測試框架,IBM Rational Robot(歷史悠久的老牌自動化工具)與TestComplete(功能強大,可支持Web、移動端和桌面程序自動化測試的付費工具),相比較于WebDrIver,它們對于自動化腳本開發者而言都不夠“開放”(可擴展)和“自由”(可封裝),或多或少都有一些局限性,當然這樣并不是說WebDriver就沒有局限性,對于GUI桌面程序界面WebDriver目前就束手無策,必須借助其他輔助工具,但這并不妨礙我對WebDriver的喜愛,因為對于Web端的自動化測試,使用WebDriver可以滿足我對頁面95%以上的覆蓋,并且在它的基礎上快速寫出一套符合自己項目的自動化測試框架。


二、準備工作

在開始自己項目的自動化測試之前,我們最好已經完成了下面的準備工作:

1、熟悉待測系統

對項目的待測系統整體功能和業務邏輯有比較清晰的認識。

2、編寫系統的自動化測試用例大綱

這一步主要是讓我們在編碼前,按優先級將系統可實施自動化測試的部分劃分出來。

3、選擇合適的工具和框架

對于WebDriver,我們可以選擇基于java或python,瀏覽器基于chrome或firefox,WebDriver版本、瀏覽器版本,用例管理選擇TestNG還是Junit等等都是考慮的因素,這里使用selenium-java 2.53.1/firefox 45/TestNG 6.8.8。


三、實現步驟

1>創建測試用例的父類BaseCase類:

每個測試用例類都繼承自BaseCase類,那么就可以將用例中的公共部分放到BaseCase類中去實現,從而簡化代碼結構和減少代碼冗余,比如:

a. 使用TestNG框架來管理用例,在BaseCase類中實現@BeforeSuite@BeforeClass@BeforeTest@BeforeMethod及其對應的After方法等;

b. 一些常用的與用例相關的方法;

c. 公共變量等。

publicclassBaseCase{

publicstaticStringurl="";

publicstaticStringusername="";

publicstaticStringpassword="";

publicstaticWebDriverdriver;

@BeforeSuite

publicvoidinitSuite(){

//初始化整個項目,如配置數據同步

}

@BeforeClass

publicvoidinitTest(){

//初始化測試類,如打開瀏覽器

driver=newFirefoxDriver();

}

@AfterClass

publicvoidclose(){

//關閉瀏覽器等操作,當然你也可以放在@AfterTest或@AfterMethod

driver.close();

}

……

2>創建用例的操作類TestAction類:

TestAction類主要封裝一些界面動作,比如點擊、輸入、移動、刷新等,與界面用戶操作(動作)相關的都可以封裝在這個類里面。

publicclassTestAction{

privateWebDriverdriver;

publicTestAction(WebDriverdriver){

this.driver=driver;

}

publicvoidrefresh(){

driver.navigate().refresh();

Log.info("F5刷新頁面");

sleep(1);

}

publicvoidmoveToElement(WebElemente){

if(e!=null){

Actionsaction=newActions(driver);

Log.info("鼠標移動到:"+getText(e));

action.moveToElement(e).perform();//鼠標移動到元素上面

}else{

Log.error("未找到對象");

}

}

publicvoidclick(WebElemente){

if(e!=null){

Log.info("點擊對象:"+getText(e));

e.click();

}else{

Log.error("未找到對象");

}

}

publicvoidsetText(WebElementelement,Objectcontent,booleanisPrintLog){

if(element!=null){

element.clear();

element.sendKeys(String.valueOf(content));

if(isPrintLog){

assertEquals(getText(element),content+"","輸入");

}

}else{

Log.error("文本框元素未找到");

}

}

}

3>封裝常用基礎控件的Hanlder類:

這一步其實放到TestAction中也沒毛病,但是將一些常用的基礎控件的操作單獨封裝起來也是可以的(看個人習慣),比如:文本控件操作類TextHandler,表格操作類TableHandler,日期選擇控件操作類DatePickerHandler等等,下面以DatePickerHandler類舉例:

publicclassDatePickerHandler{

publicstaticWebElementgetDatePicker(){

Byby=By.xpath("http://*[@class='mz-datepicker']/input");

returnBaseCase.isElementExist(by)?Page.driver.findElement(by):null;

}

publicstaticList<WebElement>getDateLinks(){

Byby=By.xpath("http://*[@class='mz-calendar-top']/a");

returnBaseCase.isElementsExist(by)?Page.driver.findElements(by):null;

}

publicstaticStringsetDate(Stringtext){

TestAction.click(getDatePicker(),0.5);

if(getDateLinks()==null||getDateLinks().size()<1){

return"";

}

for(WebElementlink:getDateLinks()){

if(BaseCase.getText(link).equals(text)){

TestAction.click(link,0.2);

break;

}

}

Log.info("選擇日期范圍:"+BaseCase.getText(getDatePicker()));

returnBaseCase.getText(getDatePicker());

}

publicstaticStringsetDateText(StringdateRange){

((JavascriptExecutor)Page.driver).executeScript("arguments[0].removeAttribute(\"readOnly\");",getDatePicker());

getDatePicker().clear();

getDatePicker().sendKeys(dateRange);

if(!dateRange.equals(BaseCase.getText(getDatePicker()))){

Log.writeInfo("選擇日期范圍失敗,實際:"+BaseCase.getText(getDatePicker())+",期望:"+dateRange);

return"";

}

Log.writeInfo("選擇日期范圍:"+BaseCase.getText(getDatePicker()));

returnBaseCase.getText(getDatePicker());

}

}

4>元素對象管理:

前面已經封裝了BaseCase類和操作類,但是頁面的元素對象該如何管理呢?這可能要根據項目的大小和元素的多少來定,下面我提供幾種常用方式:

a. 直接將元素定位的id 、name或 xpath寫在代碼中;

b. 將元素定位的表達式提取出來存放在文本、XML、yaml或json中;

c. 將元素定位的表達式提取出來存放到數據庫中;

將元素定位寫在代碼中,好處就不言而喻了,方便調試嘛,但是對于頁面元素上萬這種就不推薦了,元素對象將會變得很難管理(估計代碼中會遺留很多無用對象),但是對于頁面元素不多的情況下還是推薦它的,下面就用PageObject的方式將元素定位寫在代碼中舉例:

publicclassHomePage{

privateWebDriverdriver;

publicHomePage(WebDriverdriver){

this.driver=driver;

}

publicWebElementgetLeftNavHome(){

Byby=By.xpath("http://a[text()='首頁']");

returnBaseCase.isElementExist(by)?driver.findElement(by):null;

}

publicWebElementgetUser(){

Byby=By.xpath("http://*[@class='name']/b");

returnBaseCase.isElementExist(by)?driver.findElement(by):null;

}

}

5>用例編寫:

根據頁面創建測試用例類,類中根據頁面功能點可以寫一個或多個@Test,用例的粒度自己把握。

publicclassTestHomePageextendsBaseCase{

privateHomePagehomePage;

@Test

publicvoidtestHeaderUsername(){

if(isLogged){

TestAction.refresh();

homePage=newHomePage();

if(assertEquals(getText(homePage.getUser()),user_name,"用戶名")){

TestAction.moveToElement(homePage.getUser());

TestAction.sleep(0.5);

if(homePage.getQuit().isDisplayed()){

TestAction.click(homePage.getQuit(),0.5);

if(driver.getTitle().contains("登錄")||driver.getTitle().contains("Login")){

Log.writeInfo("退出登陸成功");

}else{

Log.writeErrorInfo("退出登陸失敗");

}

}

}

}

}

@Test

publicvoidtestXXXXX1(){……}

@Test

publicvoidtestXXXXX2(){……}

……

6>用例管理:

采用TestNG的xml文件來管理用例

<suitename="WebAutomationTest"parallel="tests"thread-count="1">

<listeners>

<listenerclass-name="your Listener"/>

</listeners>

<testname="測試用例"preserve-order="true">

<classes>

<classname="com.alany.testcase.TestHomePage"></class>

用例類往后繼續添加

</classes>

</test>

</suite>

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容