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