UI 自動化測試在有讚的實踐

作者:吳小平

部門:商業賦能

一、引言

UI 自動化是質量保障的一種重要手段,我們從分層測試金字塔模型可以看出,質量保障更多的應該依靠底層的單元測試和接口集成測試,UI 自動化測試佔比是非常小的一部分,衆所周知,UI 層的自動化測試穩定性差,成本高。然而我們團隊經過一年多的 UI 自動化測試的實踐與優化,發現我們 UI 層自動化測試相對性價比是最高的,腳本的穩定性也非常好,誤報率降到了 1% 左右,每次上線前能幫助我們迴歸系統的一些核心業務流程,下面將跟大家分享一些關於我們 UI 自動化測試的實踐經驗。

二、覆蓋合適的業務

有贊商業化團隊負責保障有贊商業化業務的產品交付,我們的核心業務是商家通過我們系統進行有贊軟件、插件的訂購,這是一套標準的電商下單、履約流程。核心用戶是有贊商家,訂購入口是 PC web 頁面和 H5 頁面。我們將商家下單流程定義成我們 P0 業務,P0 業務需要保證絕對的穩定性,任何的功能上線前都要對這塊業務進行迴歸測試,保證不會出線上問題。通過分析發現這套下單流程及相關的頁面改動較少,測試策略上適合使用 UI 自動化來保證質量,提高迴歸效率。如何判斷業務適合覆蓋 UI 自動化測試呢?原則大概如下:

基於以上原則我們發現真正適合覆蓋 UI 自動化測試的業務肯定不會太多。UI 自動化測試的穩定性會受到很多因素影響,業務流程改動、接口改動、頁面佈局改動、網絡抖動都會影響我們的腳本穩定性。我們選取業務進行覆蓋時一定要剋制,不要不斷地做加法,選取最核心需要頻繁迴歸的場景,將用例量儘量精簡,以保證最高的性價比。

三、選擇合適的框架

有贊 UI 自動化用的框架選用的是 Puppeteer + mocha,我們以往文章《有贊前端質量保障體系》裏有做過介紹,如爲什麼選擇 Puppeteer + mocha,如何做方法封裝等。

此外,Puppeteer 還可以對頁面操作的接口請求進行攔截,獲取接口返回值等,我們可以利用這些能同時操作 UI 與接口的特性來提升 UI 自動化測試腳本執行的穩定性與效率。

四、提升腳本穩定性與執行效率

4.1 元素定位

元素定位是 UI 自動化很重要的一個環節,它也是造成 UI 自動化不穩定的因素之一,比如,我們用 class 來定位元素,有些元素的 class 是動態生成的,如果開發改了 CSS 結構,新版本的 class 就變化了,元素對應的 Selector 也會變化,導致腳本不穩定。

像這種不會隨着業務變化的元素控件,我們爲了元素定位穩定,最直接的辦法,可以讓前端開發給元素增加一個專門爲 UI 自動化測試使用的 CSS 屬性,如下圖:

圖中 “立即訂購” 按鈕加了一個 testId = 'test-submit' 的屬性,這是一個自定義的屬性,只要元素一直存在,用這個屬性去定位元素就一定可以定位到,CSS 定位屬性的選擇器可以這樣寫:[testId='test-submit'],嘗試用自定義屬性定位元素,如下圖,是可以精準定位到的。

如果覺得讓開發加屬性比較麻煩,而且本身 UI 和流程改動不大,也可以按頁面組件維度來定位元素,可以先定位到組件,就是先找到父元素,再依次找到子元素。

還有一種思路是根據相鄰穩定的兄弟選擇器來定位相對不穩定的元素,如 A 選擇器相對不穩定,但相鄰的 B 元素比較穩定,那可以用 CSS 組合器。

4.2 多變元素的校驗

上面說的元素一般是不會隨着業務的變化而變化,我們獲取到元素後可以直接校驗,但如果有些元素的內容,即使開發不發佈代碼,元素也會因爲不同時間,不同業務場景而改變,該如何去做校驗呢?

上述代碼表示當遇到請求'https://www.xxx.com/xxx/xx' 接口時,獲取其返回值,該接口是後端給前端返回商品價格、週期等信息的接口,當獲取到週期信息時,我們可以計算出價格 = 週期 * 商品單價,從而作出用例校驗。

這種方式我們不僅僅用來做 UI 自動化測試,假如有些比較複雜的控件,元素不好定位,我們並不一定非要通過 UI 去校驗,我們可以在 UI 自動化執行過程中直接對接口返回值進行校驗。

4.3 執行等待機制

上圖這個界面,該商品的價格依賴於後端返回的數據,但因爲此處價格的計算時間不穩定,大部分情況都是很快可以展示,但也存在不可預期的出現時間,剛開始腳本里的實現是頁面等待 2 秒鐘,在 Puppeteer 裏,頁面等待可以用 page.waitFor(time)

但後面在腳本執行的時候還是會偶爾出現價格斷言失敗的情況,這是因爲價格計算時間在網絡等因素影響下可能會大於等待時間 2s。既然價格依賴後端接口返回的數據,那能不能等接口返回成功了,我們再去斷言價格的正確性呢?答案是可以的,Puppeteer 框架有一個方法爲 page.waitForResponse ,等待指定的 url 返回成功,這裏的 url 是在當前頁面發起的請求,可從 chrome 瀏覽器調試控制檯處查看。

控制檯查看依賴的接口:

在腳本工程裏對該方法進行了封裝,等待參數裏的 url 返回 status 等於 200,代表接口請求結束並且是成功的,當接口返回成功了,前端頁面要做的事情便是取出數據,將數據在頁面上渲染出來,考慮到渲染需要的時間,此處加個 0.1s 的等待。

UI 自動化用例腳本執行只需要在斷言前調用上述方法對需要的接口進行等待即可,爲了穩定起見,此處還加了一個控件等待 page.waitForSelector()

4.4 利用接口代替 UI 執行

業務場景舉例:

(1)創建訂單;

(2)再次創建相同商品的訂單會提示有待支付訂單,如下圖;

(3)在訂單列表進行關閉訂單才能繼續下單。 

如果每次創建完訂單或者開始創建訂單前走 UI 進行關閉待支付訂單,一是降低了 UI 自動化的穩定性,二是增加了 UI 自動化的執行時間。

對於鏈路比較長的非校驗點,但又會影響到當前校驗的功能的操作,可以用接口操作來代替。那如何在 UI 自動化框架裏發起 API 請求呢?在此,我們在框架裏引入 Axios。

Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。

我們在框架裏基於 Axios 根據常見的業務場景封裝了一個通用的 request 請求服務:get、post 請求,其中不一樣的地方是我們不需要單獨去構造 cookie,而是通過 Puppteer 的 page.cookies() 來獲取 cookie,再塞到 Axios 的 header 裏。

UI 自動化腳本的對上述封裝的接口的調用:

4.5 用例重試機制

有些腳本可能剛好因爲網絡抖動等原因執行失敗了,爲了提升測試用例的穩定性,我們可以在腳本里加入重試機制,一般測試框架都有重試機制,如我們用的 mocha 框架,重試機制非常簡單,可以在每個測試用例前加上重試語句,可以指定重試次數,如下代碼展示,如果用例失敗了,可以自動重試兩次:

4.6 截圖和日誌打印

我們執行完用例如果有失敗用例,最直接的是看頁面的展示,這個比較簡單,我們可以在測試框架鉤子函數 afterEach 里加入截圖的功能,afterEach 是 mocha 框架每執行完一個測試用例後會去執行的函數,爲了腳本穩定性,不用每個用例執行完都去截圖,而是用例失敗了才觸發截圖,所以在 afterEach 裏得判斷下當前執行完的用例是成功的還是失敗。

另外爲了能幫助我們定位是前端問題還是後端問題,我們可以將重要的接口返回值在控制檯打印出來,用的還是上面介紹過的 Puppteer 的 Response 類:

4.7 持續集成

我們 UI 自動化在兩種時間會被執行,一是項目上線前在預上線環境執行,以攔截可能會出現的 bug;二是定時在線上執行,以保證線上核心功能正確。我們把 UI 自動化的工程部署在 Jenkins 上,每次執行結果會通過企業微信發送到羣裏,並 @當前值班同學。預上線環境的執行用例一定是核心用例,執行時間會控制在 5-7 分鐘,自動化執行時間過長了,一是加大了 UI 自動化的不穩定性,二是對於部分緊急發佈的日常需求會不太友好。

五、總結

做 UI 自動化之前,要想清楚想讓 UI 自動化爲你做什麼,你想要做成 UI 自動化的的業務是不是穩定的,你要覆蓋的場景是不是你每次迴歸測試必須要測試的,當腳本跑起來的時候,它的不穩定因素是什麼?UI 自動化也不僅僅是驗證 UI 層相關的內容,也可以通過 UI 路徑來驗證接口的業務邏輯。UI 自動化測試是一把雙刃劍,不要一味追求覆蓋率,覆蓋合適的場景才能形成最高的性價比。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/vcPyNbgRNsmYhSaxSypL2A