有贊 WEB-UI 自動化實踐

概述

Bee 是由有贊 QA 開發的 UI 自動化工具,並以此實現了 web 端和 wap 端的核心業務的自動化。旨在簡化開源工具提供的接口,方便 UI 自動化測試用例的設計。css

Bee 整個框架是基於 selenium 和 selenide 設計的。框架對 selenium 和 selenide 提供的接口進行了二次封裝以知足平常的用例設計,二次封裝後的接口解決了一些元素加載,元素定位解析等問題,可讓用例設計變得更加簡便。
Bee 能支持 Web 和 Wap 頁面的元素定位以及操做,其中 Selenide 主要支持 Web 頁面的元素操做,Selenium 支持 Wap 頁面的元素操做。html

Bee 爲何會採用 Selenide+Selenium 的模式。緣由一,其實框架設計的初衷是想所有依賴 Selenide 來完成 Web 和 Wap 的自動化,Selenide 對於做者來講是一個全新的開源框架,很想窺探一二; 緣由二,Selenium 可無縫接入。在實踐過程當中發現 Selenide 還不能支持 Wap 頁面,知足不了平常的測試需求,好在框架能夠很容易的嵌入 Selenium 從而實現了 Wap 頁面的自動化,也正是 Selenide 和 selenium 有這個特性,因此在框架設計初期纔敢放心的嘗試採用Selenide;緣由三,在實踐中的切身體會 Selenide 對頁面元素的處理會比 Selenium 平滑的多,由於 Selenide 其自己也是對 Selenium 的一個二次封裝,對 Selenium 的接口也作了不少的優化。前端

Bee 目前支持的環境爲:mac、chrome,整個框架支持可擴展。git

對於 Selenide 和 Selenium 的原理不在本文中贅述,你們能夠到網上學習瞭解。
Bee 開源地址:beeyz,歡迎交流。github

用例設計

圖片描述
按照實際的業務流程調用對應接口來實現 WEB-UI 自動化測試用例。case 層可調用 service 層和 pageObject 層的接口,pageObject 是對每個頁面元素的一個封裝,service 是對一個經常使用的業務模塊功能的封裝。好比一個營銷秒殺的測試用例,須要依賴登入、建立商品,這兩個業務功能就能夠直接調用 service 中的接口。秒殺活動的建立就能夠調用 pageObject 中的接口,而後按照秒殺的業務流程,在測試用例中把這些接口串起來就造成了一個 UI 自動化測試用例,詳細細節接下去會舉例說明。web

設計用例的靈活度取決於 pageObject 封裝的顆粒度,顆粒度越小越容易在用例層設計出新流程的測試用例。用例層使用了 testng,可按照實際的需求靈活設計一個測試用例。推薦在封裝 pageObject 接口的時候,顆粒度定義的越小越好,方便用例的擴展和維護。pageObject 封裝的接口就至關於一個原子,原子粒度越小越方便組裝成新的用例。相反若是粒度太粗維護上會不太方便。參考代碼:
圖片描述
截圖是一個秒殺用例。建立活動以前,須要登入有贊微商城後臺,登入操做已封裝到 loginService,直接調用 service 層的接口,不須要在乎這個步驟的細節;登入以後要指定一個商品參與秒殺活動,普通商品建立已封裝到 goodsService,直接調用 service 層的接口,不須要在乎這個步驟的細節;接着是建立秒殺活動,建立秒殺活動的全部業務步驟都封裝到 seckillPage,這就是個 pageObject 的實現,也是用例設計中最主要的環節。最後把這幾個步驟串起來就造成了一個秒殺活動的測試用例。用例結構清晰,組裝簡單。算法

框架介紹

一、工程結構

整個工程基於 selenide & selenium,採用 pageObject 模式搭建起來。技術結構:selenide+selenium+testng+reportng+spring。下面對工程中的幾個重要模塊作介紹。
圖片描述spring

1.1 dataprovider — 數據層

爲了實現測試數據和測試用例分離而採起的一種方法,數據模型在 model 中定義,具體的測試數據則在 dataprovider 中初始化。chrome

1.2 driver — 接口層

對 web 頁面全部元素的操做都是在這裏定義接口並實現的。driver 對 selenide&selenium 提供的接口作了二次封裝,對外提供封裝後的接口。common 實現了一些和接口相關的公共方法,好比模擬鍵盤按鈕等,目前 common 封裝的方法很少,大多功能均可以經過 selenide&selenium 實現。driver 層對開源工具接口作了二次封裝,想要驅動一個瀏覽器還有一個必不可少的工具 —— 瀏覽器驅動,這個驅動放在 resources 裏,驅動的版本必須與被測瀏覽器版本相匹配。shell

1.3 listeners — 監聽器

爲了提升框架自己的容錯能力監聽一些事件。目前實現了:1. 監聽用例測試結果,可對不一樣的測試結果監聽器作不一樣的處理;2. 失敗測試用例重試的監聽,一個 fail 的用例最多可重試3次。

1.4 model — 數據模型

爲了實現測試數據和測試用例分離而採起的一種方法,具體的測試數據在 dataprovider 中初始化。能夠對一個業務流程中須要測試數據的元素在一個 model 中定義出來,方便管理和代碼閱讀。

1.5 pageObject — 業務層

pageObject 模式,接口形式封裝每個頁面須要用到的元素,實現上只要作兩步:肯定元素的定位方式;調用 driver 中對應的操做接口。driver 的接口實現包含了必定的容錯能力,但並非全面的,有些頁面獨特性或者組件的獨特性單純調用 driver 的接口並不能保證測試用例的穩定性,此時就須要在 pageObject 的接口實現中加入一些容錯算法,確保用例穩定性。
實際操做的經驗是 pageObject 對元素封裝的顆粒度越小,在用例設計層設計測試用例就越靈活,能夠像組裝工具那樣組裝出一個新的測試用例。參考代碼:
圖片描述

1.6 service — 提供業務功能

一個業務流程不少時候依賴其餘業務模塊功能,爲了方便設計一個測試用例,也爲了不重複造輪子,service 層就提供了一些經常使用的業務功能,好比登入、建立商品等。依賴方只須要在 service 層調用便可。

二、功能優化

Bee 對 selenide&selenium 作二次封裝的同時也對接口作了些優化,框架的初衷是使設計一個 UI 用例儘量的易設計、易讀、易維護。

2.1 接口優化

直接調用 selenide 或者 selenium 的接口常常會遇到些使人頭疼的問題,好比網絡問題使頁面 loading 太慢,須要操做的元素還沒展現出來,這種狀況就會常常報元素找不到的 error,用例執行失敗,但實際上這種報錯不是一個 bug,測試結果是無效的。爲了提升誤報率 driver 層接口實現了等待元素加載的功能,使用的關鍵接口:Selenide.$(elementLocator).waitUntil(Condition.appears, timeout)。參考代碼:

`/**
     * 檢查元素加載狀況
     * @param elementLocator
     * @param timeout
     * @return
     */
    private boolean checkElementLoad(By elementLocator, long timeout){
        try {
            Selenide.$(elementLocator).waitUntil(Condition.appears, timeout);
            return true;
        }catch (Exception ex){
            throw new RuntimeException(ex);
        }
    }
/**
     * 若是沒有找到元素拋null異常
     * @param element
     * @param timeout
     * @param elementType
     * @return
     */
    private By isElementLoaded(String element, long timeout,String ...elementType){
        By elementLocator = null;
        int count = 4;
        long partTimeout = timeout/count;
        for(int i=0; i<count; i++) {
            elementLocator = waitingForElementLoad(element, partTimeout, elementType);
            if(null != elementLocator){
                break;
            }else if (null == elementLocator && (count-1) == i) {//元素爲null拋出異常
                log.error("Web頁面元素:{} 沒法定位",element);
            }
        }
        return elementLocator;
    }`

概述中提到過 selenide 自己就是對 selenium 的一個二次封裝,因此 selenide 對元素的操做會比 selenium 平滑的多。在頁面加載方面 selenide 自己有作優化,再在 click、input 等操做接口中加入 waitUntil 的判斷可最大限度的等待一個元素的加載從而提升測試用例的穩定性。

2.2 元素定位統一入口

接觸過 UI 自動化用例設計的同窗會比較清楚,想經過 selenide&selenium 操做一個元素,其中必不可少的就是對元素定位的描述,通俗的講就是要通知接口在當前頁面操做哪一個位置上的元素。定位一個元素的方法不少,經常使用的有 id,name,css,xpath 等,對應不一樣的定位方法 selenide&selenium 在處理上也給出了不一樣接口。這從維護角度上來考慮顯然不是最好的。最好的作法就是用例設計者只管元素定位和操做事件的調用,而事件實現上走了哪一種渠道最好是無感知,無需維護的。對此框架封裝了一個方法供 driver 調用,主要功能就是解析描述元素的字符串自動判斷是 id、css 仍是 xpath。

2.3 失敗測試用例重試

網絡緣由等不肯定因素會致使測試用例失敗,這種外部因素致使的失敗通常都會認爲它是無效的,爲了提升測試報告的可信度,增長了失敗用例重試的機制。具體作法是實現一個用例測試結果的監聽器,當監聽器監聽到一個 fail 的結果,會觸發重試,失敗用例最多重試 3 次。

三、元素定位

UI自動化用例其實能夠分紅兩部分,1. 定位元素;2. 調用接口操做該元素。其中定位一個元素的方法不少,經常使用的有 id,name,css,xpath。實際設計中選擇哪一種定位方法通常會在維護角度上考慮的會多一些,由於如今的服務器性能配置等都很優秀,因此跑一個WEB-UI用例能夠不用考慮性能問題。從維護成本上考慮會優先選擇 id、name,其次 css,最後用 xpath。

咱們並不能保證每個 web 系統的全部元素都能給你提供一個惟一 id 或者惟一的 name,固然若是能和前端開發達成合做這就是一件很美好的事情了,通常狀況下咱們都須要面對沒有 id 和 name 這兩個屬性的狀況。這時咱們就可使用 css 樣式,不少時候 css 樣式是能知足咱們的定位需求。固然在這些都不提供給咱們的狀況下就只能選擇 xpath,使用 xpath 的優勢 1. 易獲取,主流瀏覽器只要打開「查看」就能夠經過 copy 輕鬆獲取到;2. 頁面上的元素均可以用 xpath 來描述;缺點,不穩定,大量使用的話會給用例維護產生很大的負擔。
xpath 通常只要前端在頁面上作一下小調整用例就必須從新維護,在不得不使用 xpath 的狀況下爲了減小從此的維護量可對 xpath 作一些優化,能夠減小 xpath 的路徑長度提升穩定性。如下是實踐過程當中最長用到的幾種類型:

  1. 依靠本身的屬性文本定位,如 //input[@value=‘XXXXX’]
  2. 包含指示性字符,如 //input[contains(text(),’指示性字符’)]
  3. 巧妙使用 descendant,如 //*[@id=‘app-container']/descendant::input

CI集成

用例設計完成以後就能夠加入集成建設,讓UI自動化用例在集成環境中發揮做用。測試報告展現使用 reportng。jenkins 的插件能夠很好的把 report 呈現出來,因此 reportng + jenkins 是一個很不錯的組合。
圖片描述
搭建的步驟:

  1. 搭建一個 jenkins。
  2. 一臺用於跑 UI 自動化用例的服務器。
  3. 將服務器配置成 jenkins 的一個節點。
  4. jenkins 建立 job,job 中須要使用的插件包含 Git、Excute shell、Editable Email Notification、Publish HTML reports。其中 editable email notification,支持郵件提醒,是個很不錯的插件。支持 html report 格式,附件功能。

常見報錯

使用 Bee 過程當中常常會遇到些問題,這裏作下總結方便 debug。

  1. 某些頁面不滾動。有時候一屏展現不了全部的元素。理論上 selenide 或者 selenium 在一個頁面中查找一個元素是能夠自動執行滾屏,但有些時候滾屏會失效,此時就須要在測試用例中實現滾屏查找元素。

解決方法:void scrollToElement(String element,String …elementType)

  1. 有些輸入框不能被 input 接口正常操做。實踐過程當中在日曆控件中遇到過,元素定位什麼的都對,但就是不能正常被操做。

解決方法:void triggerInput(String element,String …elementType),該接口起到一個觸發的做用,實際操做中遇到相似的狀況能夠把它當作一種嘗試。

  1. 按鈕不能被 click 接口正常操做。button 元素定位徹底正確。且在「檢查」窗口中看到的也是 button 屬性。

<button type="button" class="zent-btn-primary zent-btn-large zent-btn">肯定</button>
解決方法:調用接口 void clickByText(String text)

  1. 發現 selenide 或者 selenium 的某些接口不能 work 了,此時最大的可能就是瀏覽器升級了。

解決方法:升級瀏覽器驅動

  1. 元素不可見。有一種元素能在頁面上正常展現但對於工具來講它是不可見的,這是由於在通常狀況下元素可見須要知足如下幾個條件:visibility!=hidden ; display!=none; opacity!=0; height、width都大於0;對於 input 標籤,沒有 hidden 屬性。如截圖就是 opacity=0 的實例。

圖片描述

解決方法:調用接口 void clickByJs(String element,String ... elementType)

結束語

Bee 是在開源工具的基礎上作了些優化,目前爲止 Bee 更多的是在 driver 層作了些努力,數據層、業務層以及用例層的解決方案還有很大的提高空間。實現一個 WEB-UI 自動化用例主流的方法有錄製和代碼實現這兩種,其實兩種方法各有優劣。

Bee 還不完美,後期還需繼續努力。感謝一直以來支持 Bee 開發的小夥伴,有你有贊,有你有 Bee。
圖片描述

相關文章
相關標籤/搜索