自動化測試(10) | Selenium Java 封裝

WebDriver 封裝

歡迎閱讀WebDriver封裝講義猾愿。本篇講義將會重點介紹Selenium WebDriver API的封裝的概念和方法幌衣,以及使用封裝進行自動化測試的設(shè)計喇闸。

WebDriver API 封裝

封裝的概念

從之前的講義和學(xué)習(xí)中沧竟,我們知道短纵,WebDriver API的調(diào)用以及自動化測試远舅,我們也初步接觸了線性測試闰蛔、以及模塊化自動化測試和數(shù)據(jù)驅(qū)動測試,那么回顧之前的內(nèi)容图柏,我們不只是可以利用WebDriver提供的一系列的定位符以便使用元素定位方法序六,我們這里開始嘗試封裝后調(diào)用。首先蚤吹,我們從封裝的概念開始例诀。

封裝是一個面向?qū)ο缶幊痰母拍睿敲嫦驅(qū)ο缶幊痰暮诵膶傩圆米牛ㄟ^將代碼內(nèi)部實現(xiàn)進行密封和包裝繁涂,從而簡化編程。

所謂“對象”二驰,形象地說扔罪,我們可以把它理解為一塊積木。設(shè)計積木的人需要設(shè)計積木的外觀與形狀桶雀,還有內(nèi)部的材質(zhì)矿酵。堆積木的人對于內(nèi)部的材質(zhì)并不關(guān)心妆兑,他們只需要根據(jù)不同的外觀與形狀來決定堆放的位置相种。因此,對于開發(fā)者而言圈驼,要設(shè)計面向?qū)ο蟮某绦虬擦疲瑫r會是兩個迥然不同的身份:設(shè)計者與使用者障般。

先談?wù)勈褂谜咝伞J褂谜叩纳矸荼醒保褪抢靡呀?jīng)提供給你的所有對象,根據(jù)需求哪自,設(shè)計出自己需要實現(xiàn)的程序丰包。就如堆積木的過程禁熏。這恰恰是面向?qū)ο缶幊痰膬?yōu)勢所在壤巷,那就是“對象的重用”。已經(jīng)設(shè)計好的對象瞧毙,可以被不同的使用者調(diào)用胧华,這些功能既然已經(jīng)實現(xiàn),對于使用者而言宙彪,當然就免去了自己去設(shè)計的過程矩动。正如堆積木那樣,既然有了現(xiàn)成設(shè)計好的積木释漆,使用者所要做的工作就是把這些積木最后組合起來悲没,堆成不同的形狀。WebDriver所提供的類庫男图,就是這樣的積木示姿。那么我們以下的操作將會基于上述的定位符進行定位操作。

前面說到對象好比是一個積木逊笆,設(shè)計者需要定義好這個積木的外觀和形狀栈戳,也要考慮積木內(nèi)部的制作,例如選用的材質(zhì)难裆,以及是空心還是實心子檀。如果將這個積木剖開來看,實際上該對象應(yīng)分為內(nèi)乃戈、外兩層褂痰。由于使用者只關(guān)心外部的實現(xiàn),因此設(shè)計者就需要考慮症虑,哪些實現(xiàn)應(yīng)暴露在外脐恩,哪些實現(xiàn)應(yīng)隱藏于內(nèi)。這就體現(xiàn)了對象的封裝的思想侦讨。

簡而言之驶冒,封裝就是把原始和原生的方法進行再包裝苟翻。將原始的代碼用心的代碼包裝起來,通過對新代碼的調(diào)用骗污,來使用原始的代碼的過程崇猫。

封裝的好處

對Selenium進行封裝的好處主要有如下三個方面:

  • 使用成本低
    1. 不需要要求所有的測試工程師會熟練使用Selenium,而只需要會使用封裝以后的代碼
    2. 不需要對所有的測試工程師進行完整培訓(xùn)需忿。也避免工作交接的成本诅炉。
    3. 測試人員使用統(tǒng)一的代碼庫
  • 維護成本低
    1. 通過封裝,在代碼發(fā)生大范圍變化和遷移的時候屋厘,不需要維護所有代碼涕烧,只需要變更封裝的部分即可
    2. 維護代碼不需要有大量的工程師,只需要有核心的工程師進行封裝的維護即可
  • 代碼安全性
    1. 對作為第三方的Selenium進行封裝汗洒,是代碼安全的基礎(chǔ)议纯。
    2. 對于任何的代碼的安全隱患,必須由封裝來解決溢谤,使得風(fēng)險可控瞻凤。
    3. 使用者并不知道封裝內(nèi)部的代碼結(jié)構(gòu)。

封裝的目的

封裝世杀,最終為了實現(xiàn)自動化測試框架阀参。在自動化測試領(lǐng)域,有一個經(jīng)典的問題:“既然可以編寫或者通過record & playback可以做一個腳本瞻坝,那么為什么還需要自動化測試框架呢蛛壳?”簡而言之,就是為什么需要如此這般麻煩的設(shè)計和編寫自動化測試框架所刀,不是原本已經(jīng)可以做自動化測試了么衙荐?

這個回答可以很“官方”,從維護性勉痴、重用性赫模、安全性和成本等角度可以回答。

在這點蒸矛,就好比是建造房子瀑罗。在沒有設(shè)計框架的基礎(chǔ)上,我們或許可以建造一個樓房雏掠,最多也就三兩層吧斩祭;但是對于一份經(jīng)過完整設(shè)計的圖紙,人們可以建造出高樓大廈乡话。

封裝摧玫,就是把基礎(chǔ)的石頭等建材,通過我們的個性化的方法,將地基可用而安全的搭建好诬像。是自動化測試框架的基石屋群。

自動化測試模型

自動化測試模型.png
  1. 封裝 Selenium 為 BoxDriver
  2. 在 測試用例中,實例化 BoxDriver坏挠,產(chǎn)生 bd 對象
  3. 使用 bd 對象芍躏,構(gòu)造 業(yè)務(wù)模塊的實例化對象,產(chǎn)生 common
  4. 使用 common 在測試用例中降狠,構(gòu)建測試步驟
  5. 使用數(shù)據(jù)驅(qū)動的外部數(shù)據(jù)对竣,通過讀取,進行測試
  6. 執(zhí)行整個用例

使用封裝進行自動化測試

封裝技術(shù)

  1. 面向?qū)ο蟮木幊?/li>
  • 類:模板榜配,設(shè)計
  • 構(gòu)造方法
  • 成員變量
  • 成員方法
  • 類的實例化產(chǎn)生對象
  • 實例化過程: new 關(guān)鍵字
  • 實例化的方法: 類名(參數(shù))--> 構(gòu)造方法
  • 實例化過程相當于 類執(zhí)行了構(gòu)造方法否纬,產(chǎn)生了 this
  • 實例化出來的對象,可以訪問成員方法
  1. 封裝:做一個模板蛋褥,這個模板有webdriver所有的功能
  • 封裝 webdriver临燃,自動化 WebUI 測試
  • 封裝 Appium,自動化 APP UI 測試
  • 封裝 自定義的 Web接口 Driver
  1. 其他公司的開源框架

封裝示例

測試腳本:以下的腳本

  • 找到一個指定輸入框(selector)壁拉,并且輸入指定的字符(text)

    type(selector, text)

    不用在業(yè)務(wù)邏輯中谬俄,使用多次的 findElement(By.id(...))

    public void type(String selector, String text) {
      WebElement we = this.locateElement(selector);
      we.clear();
      we.sendKeys(text);
    }
    

    ?

  • 找到一個可以點擊的元素(selector)柏靶,并且點擊(click)

    click(selector)

    public void click(String selector) {
      this.locateElement(selector).click();
    }
    

    ?

  • 找到一個指定的frame弃理,并且切換進去

    switchToFrame(selector)

    public void switchToFrame(String selector) {
      WebElement we = this.locateElement(selector);
      this.baseDriver.switchTo().frame(we);
    }
    
  • 找到一個指定的select,并且通過index進行選擇

    selectByIndex(selector, index)

    public void selectByIndex(String selector, int index) {
      WebElement we = this.locateElement(selector);
      Select s = new Select(we);
      s.selectByIndex(index);
    }
    

    ?

以上的代碼是封裝了locateElement()的幾種方法屎蜓,在具體使用封裝過的代碼的時候痘昌,只需要簡單的調(diào)用即可。接下來的重點炬转,是介紹 locateElement(selector)的封裝方式辆苔。

  • 查找元素:findElement(By...)
  • 支持各種的查找:8種方式都需要支持,必須通過 selector 顯示出分類
    • selector中需要包含一個特殊符號
    • 實例化 封裝好的類的時候扼劈,需要約定好是什么特殊符號
      1. 強制性用硬編碼 hard code來實例化驻啤,例如 , 或者 ? 或者 其他非常用字符 =>
      2. 或者,構(gòu)造方法中荐吵,傳遞 this.byChar
  • 要把查找到元素的返回給調(diào)用的地方:必須要有返回值骑冗,類型是 WebElement
private WebElement locateElement(String selector) {
  WebElement we;
  // 如果定位符中 有 分隔符,那么就從分隔符處分成兩段
  // 第一段是By
  // 第二段是真正的定位符
  // 如果沒有分隔符先煎,就默認用 id 定位
  if (!selector.contains(this.byChar)) {
    // 用 id 定位
    we = this.baseDriver.findElement(By.id(selector));
  } else {
    // 用 分隔符 分成兩個部分
    String by = selector.split(this.byChar)[0];
    String value = selector.split(this.byChar)[1];
    we = findElementByChar(by, value);
  }
  return we;
}
  • 接下來的重點贼涩,是實現(xiàn) findElementByChar(by, value)
private WebElement findElementByChar(String by, String value) {
  WebElement we = null;
  switch (by.toLowerCase()) {
    case "id":
    case "i":
      we = this.baseDriver.findElement(By.id(value));
      break;
    case "css_selector":
    case "css":
    case "cssselector":
    case "s":
      we = this.baseDriver.findElement(By.cssSelector(value));
      break;
    case "xpath":
    case "x":
      we = this.baseDriver.findElement(By.xpath(value));
      break;
    case "link_text":
    case "link":
    case "text":
    case "linktext":
    case "l":
      we = this.baseDriver.findElement(By.linkText(value));
      break;
      //TODO: other by type
  }
  return we;
}

使用上面的封裝類,就需要指定特定的 selector

類型 示例(分隔符以逗號,為例) 描述
id "account" 或者 "i,account" 或者 "id,account" 分隔符左右兩側(cè)不可以空格
xpath "x,//*[@id="s-menu-dashboard"]/button/i"
css selector "s,#s-menu-dashboard > button > i"
link text "l,退出"
partial link text "p,退"
name "n,name1"
tag name "t,input"
class name "c,dock-bottom

調(diào)用示例

void logIn(String account, String password) throws InterruptedException {
  BoxDriver driver = this.baseDriver;
  driver.type("account", account);
  driver.type("password", password);
  driver.click("submit");
  // 點擊登錄按鈕后薯蝎,需要等待瀏覽器刷新
  Thread.sleep(2000);
}

自動化的測試代碼示例

@Test
public void test01Login() {
  common.openPage();
  common.logIn(member.getAccount(), member.getPassword());
  expectedUrl = this.baseUrl + "sys/index.html";
  Assert.assertEquals(driver.getCurrentUrl(), expectedUrl, "新用戶登錄失敗");
  common.logOut(lang);
}

封裝需要注意的部分

  • 方法有無返回值遥倦、和參數(shù)

    • 如果有返回值:確保代碼所有的路徑都會有返回值

      public WebElement getElement(){
        if (xxx) {
          return yyy;
        }
      }
      // 上述代碼會報錯,如果xxx條件不符合占锯,就沒有返回值的路徑了袒哥。
      
    • 如果有參數(shù)缩筛,確保非值類型的參數(shù)是非空的 不是 null

      public void type(Driver driver){
        driver.xxx()
      }
      // 如果driver是null,那么xxx會直接報錯堡称。 NullPointerException錯誤異常
      
    • 如果有較多的分支語句歪脏,需要注意 break的使用

      public WebElement getElement(String selector){
        switch(selector.toLowerCase()){
          case "id":
          case "i":
            driver.findElement(By.id(xxx));
            break;
          case "x":
            xxx
        }
      }
      // 注意需要填寫break
      

      在python中,不支持switch語句粮呢,python使用的是 if ... elif

      def get_element(selector):
          if selector == "id" or selecor == "i":
              driver.find_element_by_id(xxx)
          elif selector == "x":
              xxx
      

      ?

  • 封裝中婿失,WebDriver對象的傳遞

    • WebDriver應(yīng)該是在封裝的類中,唯一存在啄寡。

      class AutomateDriver(){
        public click(String selector){
          WebDriver driver = new FirefoxDriver();
          driver....
        }
        
        public type(String selector, String text){
          WebDriver driver = new FirefoxDriver();
          driver....
        }
      }
      // 上述代碼中豪硅,會打開多個火狐瀏覽器
      // 正確的做法:聲明一個全局的類的成員變量,進行賦值使用挺物。
      

      ?

關(guān)于Firefox Profile的使用

在做自動化測試的時候懒浮,經(jīng)常會發(fā)現(xiàn)Firefox 被初始化,提示收藏夾等识藤,遮住元素窗口砚著。因為Firefox每次都以默認的Profile 加載全新的Firefox,例如如下圖片:

Snap1.jpg

在這樣的情況下痴昧,我們需要專門準備一份獨立的Firefox Profile進行使用稽穆。步驟如下

  1. 在命令行中進入Firefox的安裝目錄,然后輸入 firefox -ProfileManager -no-remote

    Snap2.jpg
  2. 然后在彈出的窗口中赶撰,新建一個Profile舌镶,記錄地址。

    e5792a15-e7ed-39fa-bf46-5505c54923a5.png
  3. 根據(jù)剛剛的地址豪娜,打開Profile所在的文件夾:C:\Users\Linty\AppData\Roaming\Mozilla\Firefox\Profiles

    Snap3.jpg
  4. 復(fù)制 einy9uds.selenium文件夾到 base目錄中餐胀。

    Snap4.jpg
  5. 修改代碼 automate_driver.py

    def __init__(self, by_char=",", firefox_profile=None):
        """
        構(gòu)造方法:實例化 BoxDriver 時候使用
        :param by_char: 分隔符
        :param firefox_profile:
        可選擇的參數(shù),如果不傳遞瘤载,就是None
        如果傳遞一個 profile否灾,就會按照預(yù)先的設(shè)定啟動火狐
        去掉遮擋元素的提示框等
        """
        if firefox_profile is not None:
            firefox_profile = FirefoxProfile(firefox_profile)
            driver = webdriver.Firefox(firefox_profile=firefox_profile)
            try:
                self.base_driver = driver
                self.by_char = by_char
                except Exception:
                    raise NameError("Firefox Not Found!")
    
  6. 修改代碼 xxx_test_cases.py

    profile = "base\\einy9uds.selenium"
    self.base_driver = AutomateDriver(firefox_profile=profile)
    
  7. 完畢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸣奔,一起剝皮案震驚了整個濱河市墨技,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溃蔫,老刑警劉巖健提,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伟叛,居然都是意外死亡私痹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來紊遵,“玉大人账千,你說我怎么就攤上這事“的ぃ” “怎么了匀奏?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長学搜。 經(jīng)常有香客問我娃善,道長,這世上最難降的妖魔是什么瑞佩? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任聚磺,我火速辦了婚禮,結(jié)果婚禮上炬丸,老公的妹妹穿的比我還像新娘瘫寝。我一直安慰自己,他們只是感情好稠炬,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布焕阿。 她就那樣靜靜地躺著,像睡著了一般首启。 火紅的嫁衣襯著肌膚如雪暮屡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天闽坡,我揣著相機與錄音栽惶,去河邊找鬼愁溜。 笑死疾嗅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的冕象。 我是一名探鬼主播代承,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渐扮!你這毒婦竟也來了论悴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤墓律,失蹤者是張志新(化名)和其女友劉穎膀估,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耻讽,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡察纯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饼记。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡香伴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出具则,到底是詐尸還是另有隱情即纲,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布博肋,位于F島的核電站低斋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匪凡。R本人自食惡果不足惜拔稳,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锹雏。 院中可真熱鬧巴比,春花似錦、人聲如沸礁遵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佣耐。三九已至政勃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兼砖,已是汗流浹背奸远。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讽挟,地道東北人懒叛。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像耽梅,于是被迫代替她去往敵國和親薛窥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容