【Android測試】UI自動化代碼最佳化之路

來源:互聯網
上載者:User

標籤:erp   電話   找不到   能力   目的   生命週期   btv      很多   

關於UI自動化的抱怨

  聽過不少人這樣講 “UI自動化非常不穩定,需求一改,介面一遍,全部都費了”。我相信做過的人可能也會有同感。既然這個問題一直都是存在的,那麼為什麼沒有人仔細分析原因呢?

  我的老闆george曾舉了這樣一個例子:每當需求變化的時候,開發沒有跳起來,反而是測試跳了起來。然後不斷的抱怨,介面元素全都改了,我的自動化的用例全部都要廢棄掉了。那麼我們是否想過,為什麼開發可以從容不破的應對產品不斷變化的需求?而我們卻不能呢?

  

  業內不少人也都放棄了UI自動化,覺得介面測試才是最有意義的,的確介面測試相對於UI自動化的來說,確實穩定的多,但是難道我們測完介面後,就不需要再測試UI了嗎?UI層可是最貼近使用者,也就是直接給使用者最直接的一層,我們真的要放棄嗎?換句話說,如果用戶端開發在分層做的特別差的時候,用戶端的介面測試真的會那麼好做嗎?按下一個home鍵後再回來,onStop、onResum等一些生命週期裡的函數恐怕都很難應付的過來吧。說了這麼多,還是回到正題吧,講一講如何寫好我們的UI自動化測試工程。(注意,這裡是工程,不是指令碼,指令碼是很隨意的,隨便寫兩句用來測試的,工程就代表是一個可以交付給使用者使用的,我們可以認為開發的代碼是我們要交付給使用者的產品,當然我們的測試代碼同樣也是要交付給使用者的產品,所以後面統一叫測試工程)

 

 

簡陋的測試代碼

  首先來看看之前我們的UI自動化的代碼是怎麼寫的:

  

  這裡我使用了Espresso+Uiautomator2架構來進行舉例,忽略文法,只說結構的話是不是看上去很熟悉,大家在起初寫測試代碼的時候應該也是這樣的一個方式吧:在測試函數中完成所有的操作實現,如果是通用的操作,可能去封裝一個函數,當然有的時候還會用到setup進行初始化,使用teardown來進行收尾。我想說如果是這樣的寫法的話,我們的確很難應對變化的需求和介面了,恐怕測試架構的更新換代,都能讓我們的測試代碼全部推翻重寫。其實綜合起來我們之前的代碼存在這樣的一些問題:

  1、用例層包含了太多和源碼相關的內容,只要源碼改動,用例內容必改。

  2、用例層直接調用原架構內容進行實現,無法處理一些通用的異常情況,也不能適應工具架構的變化。

  3、通用的一些方法(例如登入),多個用例集(**Test類)中的用例(test**()函數)可能都需要複用,需要處理好調用的方式。

  4、啟動Activity這樣的操作不必要每個用例集都寫,可以最佳化一下,抽象出基類。

  因此針對這些地方,我們需要進行最佳化,我們接著往下看。

 

 

關鍵字驅動

  yoyo(GT的開發)建議我使用這樣的一套用例編寫的方案,就是基於關鍵字驅動的方案,在用例層的實現剝離和原始碼相關的部分,使用高度抽象。這樣的話只要業務的流程不變,介面任意怎麼修改,我們都不需要去修改用例層的代碼。整個架構的實現結構如下:

   

  這裡如果大家看類圖有些吃力的話,可以先看看UML類圖介紹。這裡先大致說下這些類別模組的作用:

  BaseTest:所有Test類的基類,也就是測試案例的基類,裡面實現ActivityTestRule來啟動Activity,如果有需要的情況下可以實現BeforeClass和AfterClass,這兩個在整個命令的運行周期內只在開始和結束的地方執行一次。

  用例Test:具體的測試案例的實作類別,這個可以理解為一個測試集,每個類中有若干test函數,每個函數就代表一個測試案例,用例的寫法採用關鍵字驅動的方法。

  Key:用枚舉定義著所有的關鍵字。

  Command:介面類,供Word實現execute(Obj)的方法。

  FrameCommand:基類,供Word層來繼承,裡面只封裝了一個execute(Key, Obj...),主要用在AW中調用KW的實現;這裡需要注意和Command介面中execute的區別。

  Word層:即圖中Login、Enter**Page等,需要實現Command介面中的execute函數,同時繼承自FrameCommand,解釋為什麼是Word層,這裡需要把這些實現抽象成ActionWord(簡稱AW)、KeyWord(簡稱KW),而這兩者的區別就是,KeyWord中實現可複用的一些情境,ActionWord中可以包含KeyWord,實現一些很少被複用的情境。

  TestContext:將Key中關鍵字和具體的Word實現的函數進行關聯,構造一個map,使得直接通過execute關鍵字就能調用起對應的函數。

  具體實現的代碼我先不詳細解釋,我們先來看看使用這套架構後,之前實現同樣功能代碼寫成了什麼樣子:  

  

  可以看到,測試案例(這裡認為一個test***函數就是一個測試案例)這一層我們做了高度的抽象,在testPublish這個函數中沒有任何與開發原始碼或者是資源id有關的資訊了,這裡的Key.EnterPublishPage就是我們的關鍵字,具體的實現在EnterPublishPage這個AW的函數中,這樣寫用例,當我們的介面發生了大的改變,例如我們版本迭代中從發布的兩個頁面,如下所示:

  

  在新版本改變後,改成了一個介面,如:

  

  可以看到介面元素的調整還是不少的,如果之前我們可能就得廢棄之前的用例重新寫了,但是使用了關鍵字驅動後,我們的用例層的改變根本不需要做任何的修改,而對應的如果控制項ID改變後,我們只需要修改Word層即可。

  這裡說下AW和KW之間如何封裝,就代碼層面,對於編譯器來說,是沒有AW和KW之分的,我們抽象這兩層的意思就是,當有一個Word可以被多個用例複用的話,這樣我們就把它封裝起來供其他的Word使用。具體還需要在實踐過程中慢慢的體會。  

 

 

封裝測試架構

  說完了關鍵字驅動,需要說下封裝架構這一塊。看過我之前文章的朋友們應該知道我為什麼要選擇Espresso和Uiautomator,目前Google推薦使用這兩款架構,有興趣可以看看Google的這兩篇原文:

  

  那麼兩個架構同時加入到我們的測試工程應該如何去整合代碼結構內,這裡我自己使用這樣的結構,覺得還不錯的可以參考一下,首先先看下類圖:

  

  看完類圖後可能有些人已經看出來啦,沒錯這裡使用了簡單原廠模式,具體的Word層來使用工程加工出來的對象,具體的工具封裝內容封裝在FrameUiautomator和FrameEspresso裡。

  這裡主要說下針對Uiautomator的封裝,如果之前讀過我寫的《如何組織好你的測試代碼》,那麼裡面的一些思想應該比較清楚了,主要的優點就是:

  1、頁面跳轉或者非同步載入延遲出現的介面,無需再單獨使用sleep;

  2、對於系統隨機出現的可能會影響App介面的一些因素(例如Android6.0的授權彈框、電話呼入),無需再單獨處理;

  3、對於App中隨機出現的可能會遮擋正常介面的一些彈框,無需再單獨處理;

  4、所有調用封裝後架構的操作,都會記錄日誌;

  5、架構本身有斷言能力,如果在架構處理異常情況後還找不到指定控制項,這時候會並且斷言;

  6、如果需要替換架構或者架構升級,可以使用最小的成本來架構層進行改動,而不需要改動用例層和Word層。

 

 

完善其他內容

  上面主要講的是UI自動化的一些行為操作,關於斷言的問題,我這裡不想說太多,BTV做到介面上的UI元素的檢查,以及整個流程是否可以完整的走下來就可以了,如果需要驗證資料正確性等一些複雜的內容,可以參考我寫的《App任你擺布(反射技術的引入)》。我這裡說說UI自動化如果失敗了,我們怎麼排查問題?其實很簡單我這裡做的就是日誌+。

  日誌系統最關鍵的是打日誌的時機,這裡我把它埋到了BaseTest的execute()中,這樣每一次的用例調用AW或者AW中調用KW,都可以記錄下來,同時也埋到了架構的具體實現函數中,這樣架構只要操作就會記錄下日誌。這裡有個小的技巧,我在列印日誌的地方調用了下面的函數:

String classname = Thread.currentThread().getStackTrace()[3].getClassName();

  這樣就可以記錄下當時調用Log函數的當前的類的名稱了,這裡可以看下我輸出的log的樣子:

  

  是不是比較齊全了,基本上所有你想知道的資訊都可以通過log內容來獲得了。下面說說,和log的整體思路一樣,會在一些關鍵節點埋點同時也支援手動調用。因為我的工具架構是支援自身斷言的,因此我在工具架構這一層斷言的時候會加入,其他地方如果你需要特別關注的時候,也可以手動調用觸發。

  

   上面的圖是不是非常直觀,當我們的用例出現異常錯誤的時候,直接通過log和日誌即可定位到問題的所在。

 

 

結果展示

  測試結果最終對接了內部的持續整合平台和結果展示平台後是這個樣子:

  

  保證了編譯器中的結果和結果展示平台中顯示的情況一致。 

 

 

結合實踐談談

  互連網產品的迭代速度之快,各位都深有體會。做為產品品質的保障者,測試人員經常為測試時間不足而煩惱,如何打破現狀來讓現在變得更好一些,這是我們一直在思考的問題。軟體工程中有提到測試人員越早的介入到研發的流程當中,就可以越早的發現問題,從而降低發現問題的成本。因此"左移"變得非常的有必要了起來,當然左移的方式有很多,例如前幾天拜讀到的《聊聊測試“左移”那些事》這裡面主要講測試人員通過把控需求來達到左移的效果,而我上面所講到的內容都可以協助自動化實現左移的。

  想想之前我們做的UI自動化是怎麼做的呢?在版本提測之後,我們開始寫自動化,這樣自動化的主要功能就變成了迴歸和冒煙。我這裡我想說的是在開發寫代碼的時候,我們也開始寫用例層級代碼,在開發定義了介面布局後,我們就可以完善具體代碼,待開發提測時,我們就可以運行我們的用例來進行測試了。

  當然針對新老版本可能略微有所不同:

  如果是新需求的情況下,我們在需求確定的情況下就可以先組織自己的用例了,具體實現依賴開發的word層的代碼可以先空著,待開發確定之後,我們就可以及時的完善我們的word層,這樣不用等到開發提測之後,我們才開始設計我們的自動化測試案例。

  對於老的需求變更,同樣也是,首先可以看之前的用例中的關鍵字是否有可複用的東西,如果可以直接複用,那就繼續用,如果有新的步驟加進來,那麼只需要加入對應的關鍵字即可,和新需求的做法一樣,同樣在開發提測之前完成用例的編寫。

  其實在整個方案啟動之前,我就在思考這個問題。那麼這個做出來後究竟會有收益嗎?因為畢竟做完整個系統不是一件容易的事情,需要花很多的時間成本進去。那麼分析收益從哪方面入手呢?我覺定先從bug入手,於是針對最近的一次版本做了一個簡單的bug分析:
  
  從資料中可以看到,的確有一部分的bug是可以在左移階段被發現的。這裡分為BVT層級的用例和詳細模組的用例。BVT層級用例來限制開發的提測,提測前開發自己去運動這部分用例,通過才可以提測;具體功能層級的詳細模組的內容用專門針對這個版本修改或者新增的新功能。

  這就是本節想跟大家說的內容,整個過程中不管是對項目的收益或者是自己的成長,我都有所收貨,拿出來和大家進行分享,希望能協助到其他人。

 分類: 軟體測試

【Android測試】UI自動化代碼最佳化之路

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.