Selenium WebDriver Page Object Model (POM) 設計模式,若是有開發過 UI 自動化測試或是寫網路爬蟲的多少都有聽過或是看過吧!
最近剛好有幸接觸到某外商的 SDET 面試考試,題目要求使用 POM 設計 UI 自動化測試,又再度幫自己複習一遍。
想了一下,我從開始接觸 Selenium 約莫是5年吧!
從一開始的各種未知 > 新手入門 Selenium IDE > Selenium 2.0 > Selenium 3.0 一直到現在...經歷了踩過無數次的坑,算是能有一點自己的想法的吧 :D
Why?
人生總是因為這個 Why? 變的生活無法自理...
你一定會跟我一樣的問著: Python + Selenium 直接寫就好啦! 為什麼要這麼麻煩呢? 我還要學習物件導向 !? 為什麼不 function call 一 call 就好啦!
這些疑問隨著維護的程式越來越龐大搞到自己差點生活無法自理,當自己製造一堆技術債後,對工作會越來越不起勁,然後大崩潰...接著想離開公司...然後到另一間公司繼續製造技術債... ( 把自己的屎留給別人吃最棒了 XD
What?
先來想一下,假如我們不考慮其他狀況,直接果斷開始寫會如何 ?
有些痛苦,還是必須自己體會與承受 !
先設定一個目標,就把 Instagram 登入頁面當作待測頁面吧!
在不考慮註冊,忘記密碼,App Store 下載等方式...
寫個自動化測試程式來測試這個登入頁面吧!
How?
該怎麼開始? 當你接到這個要求到完成測試程式需要考量那些問題?
我想還是先把 Test Case 列下來吧 !
1. 使用者成功登入IG
2. 使用者使用不同瀏覽器登入
3. 轉跳至Facebook登入頁面
4. 使用者輸入錯誤的帳號
5. 使用者輸入錯誤的密碼
先以簡單的考量為主,列出了五個測試案例,接著開始用 Python + Selenium 實現吧!
首先會先遇到一個問題,My God! 我要下載瀏覽器的 Driver ...
(好麻煩... 算了先不解釋... 有興趣看一下這篇~~~
不管什麼設計了 ! 通通加再一起做成撒尿牛丸吧 !
如果全部參在一起,不考慮任何設計結構,程式的長相大概會像上面那個樣子。各自有各自的 driver instance 與各自的 function,然而當你遇到快速變化的使用者介面或是多變的使用者需求,這樣的設計結構會產生幾個問題 ( 當然 ! 我也曾經寫過類似的設計 Q_Q ) :
1. 程式龐大起來難以維護
2. 很難有個統一的 webdriver driver wait timeout
3. element locator 難以被 reuse
4. 提高下一個維護者離職的機率 XD
So?
如果使用了 Page Object Model Design Pattern 會是什麼樣的美好人生? 還是會是另一個大災難 ? 想像一下架構大概會是這個樣子:
將 Test Case 的位階拉到最高,成為一個可執行的 Spec,再以 Web 頁面拆分,每個頁面會是一個獨立的 Page Object 搭配 Locator 所組成。透過繼承 Base Page 的基本 Web 操作,由 Page Object 執行頁面的特定操作,例如: click_login_button, input_username ... 之類的 ( 如果做到極致,必須保持
Clean Code 的單一原則 ),Page Locator 的職責就很簡單,負責管理網頁元件的定位器,ID、NAME、XPATH ... 或是 Alert message 之類的。
來看 Code 吧 ! 先從 Test case 開始 !
至於...為什麼要這樣寫 ? 可以參考這篇。
將 Test Case 以 Gherkin 語法寫成連普通人都可以讀的懂的方式,然而它也是一個可以執行的 Spec,如此一來對所有專案相關人都有一致的溝通文件,產出測試報告時,也能夠以大家都看得懂的方式呈現。
Base Page
base_page.py 則是制定一系列的 Selenium 的 Web 基本操作,如上面所見的 methods 與統一的參數設定 ,好處有以下幾種:
1. Project 規格統一(timeout, wait...)
2. Selenium 版本更新時,改變時也不需要改動太大 (統一介面)
3. 模組化的架構能夠輕易的被重複使用,進而減少重複的程式片段
4. 透過從外部傳入的 driver 參數 僅使用一個 driver instance
Locators
Page Object
繼承 Base Page 而來的 Instagram Login Page Object 擁有一樣的基礎 Web 操作,也把 Locators 倒入至 Login Page 物件內,接著細分 Login Page 所需要的各種操作,以上面程式為例,拆分為登入、輸入、點擊、驗證...等幾個細部動作。有這些細部動作之後,再到 Test Case Step 去把每個動作串聯起來~就大功告成啦!
完整專案就到 GitHub 參考吧!
Then?
結論的部分,目前已經將 Page Object Model 導入幾個 Legacy Project,早期的專案不太注重 Unit Test 以至於需要大量的 End to End Test 去維護專案的品質。近幾年維護下來,還算是可以接受的! 不過 UI test 只要一多,自動化測試不穩定的狀況也會跟著多,可能每天都花時間在看 Fail Case 就飽了! 最根本的方式還是要把基底打好吧! 就像各類書上說的 Unit Test > Integration Test (API) > UI Test。
喔對了! 整個研發團隊的合作還是很重要的,需要有好的軟體品質,還是需要不斷的討論,藉著每次的討論,都可以有一些收穫。如果可以 QA or SDET 一起加入 Product Code Review 或是前期的 Design 是必要的,有些設計需求可以在很早期就知道,測試人員也可以幫忙檢查是否符合需求或是對於設計給一點建議。
繼續加油吧 ! 希望大家都能~好好睡覺~好好生活~好好工作 !