The web has evolved. Finally, testing has too.
事實上對於 UI 自動化測試來說,許多所謂框架之間並沒有太多差別,也從來不是影響整套測試用例是否健壯的關鍵性因素。相比之下,如何提高測試用例穩定性以及出現錯誤時 debug 的便捷性才是讓 UI 自動化測試方案落地的重要細節。
那么為什么我們還需要討論技術選型呢?首先我們來看看技術選型包含哪些部分。
通常 UI 自動化測試的技術方案分為控制(控制客戶端)、執行(運行通過特定 API 編寫的測試用例)、結果上報這幾個主要組成部分,在過去各類框架往往喜歡在執行和結果上報兩個部分提供差異化的 API 來提高開發效率,但這很難對我們開頭提到的兩個重要細節起到本質上的幫助。
隨着 Web 技術的不斷演進,Web UI 自動化測試中的控制部分也終於有了更進一步的發展,而且這一部分正是解決用例穩定性、提升 debug 能力的核心所在。
接下來就對比一下目前可選的幾種控制方案的優缺點。
selenium + webdriver
selenium 的方案最為傳統,也是目前最常見的瀏覽器控制方法。selenium 通常需要和 webdriver 配合使用,selenium 通過 webdriver 控制瀏覽器,再對上層執行層暴露 API 或 sdk。
同時 selenium 也提供 standalone server 的方案,允許執行層通過調用標准 restful API 控制瀏覽器,在這種模式下對執行層的編程語言和運行時都沒有任何限制,這也是 selenium 生態繁榮的重要原因。
優點
selenium 的 API 封裝遵循 W3C 提供的 webdriver 標准,因此 selenium 對各大主流瀏覽器的支持都不錯,如果測試場景對瀏覽器兼容性有較高的要求,需要在多種瀏覽器中執行測試用例,selenium 仍是首選。
同時由於 selenium 已經發展多年,各種解決方案也更為完善。例如並行方案 selenium grid,可以支持多節點的用例負載均衡;還有在 CI 場景下官方維護的各種 docker image 等。
不足
selenium 是一套較重的方案,選擇 selenium 意味着依賴 webdriver、java,如果執行層的編程語言不是 java,那么額外引入這些無疑是較為痛苦的。
另一方面,selenium 為主的方案一般會形成一個“測試用例 -> 測試框架 -> selenium -> webdriver -> 瀏覽器”的復雜控制鏈,鏈上每多一環就意味着 debug 的復雜度上升一級,這會讓測試用例的編寫成本顯著上升。
chrome devtools protocol
chrome devtools protocol(以下簡稱 CDP)可以看作 chrome(或其他使用 Blink 內核的瀏覽器)開放的遠程控制協議。通過 CDP 我們可以控制 DOM、Debugger 和網絡請求等瀏覽器內部領域,從而實現測試的目的。
相比之下 CDP 不依賴 webdriver 這樣的二進制文件,也不綁定特定的編程語言,理論上可以直接在測試用例文件中和 CDP 通信,控制瀏覽器。但是實際上已經有很多成熟的 CDP 封裝,大部分情況下我們使用它們而不是直接和 CDP 交互。
對 CDP 的封裝可以大致分為兩類,一類是只對網絡通信部分封裝,而不涉及啟動瀏覽器、管理瀏覽器進程等工作。例如 chrome-remote-interface 就屬於這類,只提供了良好的 js API 封裝,如果需要滿足自動化測試的需求還需要搭配 chrome-launcher 這樣的庫對瀏覽器進程進行可編程的管理。
另一類則是一體化的方案,最佳實踐是 google 自己維護的 puppeteer 項目。puppeteer 不僅負責管理瀏覽器和將 CDP 封裝成 high level 的 API,甚至還默認下載一個指定版本的 chromium 並使用,以避免本地瀏覽器版本不確定帶來的穩定性隱患。
優點
作為控制部分,CDP 的方案往往控制鏈較短,並且對編程語言沒有限制,相對而言會更加穩定,並且也帶來更好的執行速度。
chrome 在 59 版本開始引入了 headless 模式,這對 CI 流程來說有很大的幫助。過去如果需要在 linux 服務器上運行 Web UI 測試,通常都需要引入 xvfb 模擬屏幕,headless 模式則可以省去。
除此之外,CDP 相比 webdriver 標准控制能力更強,例如可以對網絡層進行監聽,從而可以輕松實現“所有網絡請求完成后開始交互”這樣的功能。
不足
CDP 方案只能兼容 Blink 內核的瀏覽器,因此對瀏覽器兼容性有要求的測試不應該選用。
不論是 CDP 還是更進一步的 puppeteer,目標都是實現一個通用的自動化工具,而不是聚焦於測試。因此其內部沒有集成測試相關的功能,例如斷言、用例編排、結果上報、執行負載均衡等等,需要繼續引入第三方庫或自行實現,這作為一個測試框架而言不夠理想。
pixabayhttps://www.wode007.com/sites/73237.html wallhavenhttps://www.wode007.com/sites/73236.html
Inject script
Inject script 的方式是指在瀏覽器打開的 Web 應用內注入測試引擎、測試用例等腳本,將測試用例執行在被測試應用的運行時中。
Cypress 和 Testcafe 這兩個測試框架是這類控制方式的實踐者,它們認為過去許多依托於 selenium 構建的測試框架的核心問題在於都是從外部控制瀏覽器和 Web 應用,執行命令或者獲取信息都需要通過網絡請求進行交互,因此交互的信息需要進行序列化。這不僅限制了交互的內容,還對 debug 帶來了極大的不便,同時網絡請求帶來的開銷也讓測試變得更加緩慢。
與之相反的是 inject script 選擇從內部控制瀏覽器,測試用例代碼將和被測試的 Web 應用運行在同一個瀏覽器運行時中,可以理解為注入的腳本即為測試客戶端,與后端建立通信,所有的操作指令都是通過 Javascipt 實現並執行,本質上只是函數的調用,客戶端和后端之間的通信僅用於測試結果的收集,不包含具體的指令執行。
值得一提的是 selenium 1 中最早采用的也是類似 inject script 的實現,但是由於當時各個瀏覽器中的 JavaScript 運行時缺乏統一的標准,執行結果不一致,因此產生了很多兼容性問題,selenium 才不得不通過標准更規范、並且有廠商支持的 webdriver 來進行控制。但時至今日,JavaScript 規范已經非常成熟,主流瀏覽器的 JavaScript 內核也都嚴格遵循規范予以實現,inject script 方案最大的弱點也就得以克服。
Cypress 和 Testcafe 的定位是完整的測試框架,並且只聚焦於完成 UI 自動化測試這一個任務,內部包含執行框架、斷言、請求 mock、結果上報等所有測試所需功能,不需要再配置其它的依賴項。
由於控制流程的改進,雙方在測試穩定性、運行速度方面都有很大的改善,可以被視作是下一代 UI 測試框架,但是兩者也因為目標場景略有不同而在一些方面各有優劣,需要根據實際使用場景進行選擇。
優點
用例執行的穩定性在兩個框架中都作為最高優先級加以解決。許多 UI 測試的不穩定性來源於不能很好的處理界面中的異步情況,而 Cypress 和 Testcafe 在指令的 API 設計中就默認所有指令均有異步情況,會自動完成 wait 的處理。
此外同一運行時的設計在測試一些現代前端框架構建的應用時有巨大的優勢,例如直接測試框架數據狀態管理(如 redux)的正確性等等,支持編寫一些更偏向白盒測試的用例。
雙方也都有官方支持的 CI 集成方案,保證在 linux 服務器環境下也能夠快速的搭建起運行環境。
不同之處在於 Testcafe 原本是商業產品,有着成熟的客戶群體和解決方案,在轉向開源之后依然能夠發揮其經驗豐富的優勢,在一些實現上更注重易用性。因此會封裝更高級的指令,例如拖拽、文件上傳等等,並且所有指令均用原生 JavaScript 實現,所以對瀏覽器的兼容性很好。還對測試用例提供了預處理器,所以用戶可以選擇用最新的 JavaScript 特性編寫用例或者使用 Typescript 這樣的超集語言。
高級功能方面 testcafe 支持通過錄制操作生成腳本,對於一些非開發人員來說提供了一定的便利性。
相比之下 Cypress 的目標不僅僅是做 selenium 的替代品,更希望成為革命性的測試框架,因此做了更多大刀闊斧的改進。
以上多次提到的 debug 問題是 Cypress 的最大優勢,Cypress 實現了 DOM 快照、操作回放、指令可視化、網絡請求監控等功能讓用例執行失敗的原因一目了然。
高級功能方面 Cypress 原生支持截屏、錄屏等功能,進一步加強 headless 模式或 CI 模式下的 debug 能力。
Cypress 另一大高級功能是對應用中的網絡請求實現監控、mock 等操作,讓一些原本通過 UI 比較難以實現的斷言可以轉為對網絡請求進行判斷。
不足
雙方的不足更多是和對方相比較之下產生的。
Testcafe 對高級功能的支持有所不足,例如錄屏和 DOM 快照等高效的 debug 方案還未實現。
Cypress 部分指令和高級功能普通 JavaScript 無法實現,需要借助 chrome extension API,因此目前並不能兼容所有的瀏覽器。並且由於特殊的控制實現方式,Cypress 不能支持跨瀏覽器、跨 tab 的測試需求,還要求被測試 Web 應用是同源的。
此外 Cypress 還有一些臨時性的不足,例如用例執行時的負載均衡等高級功能的支持還不完整,一些原生操作例如文件上傳也還需要通過 JavaScript 模擬,不過這些臨時問題都在 roadmap 上排期解決。