概述
瀏覽器兼容性是目前前端項(xiàng)目迭代中常常遇到的問(wèn)題.
每次迭代, 回歸測(cè)試需要消耗大量人力進(jìn)行手動(dòng)操作, 去覆蓋不同瀏覽器下不同業(yè)務(wù)場(chǎng)景的前端展示情況.
本文的目的即探討解決這類(lèi)問(wèn)題的一個(gè)方案: 利用分布式的UI自動(dòng)化測(cè)試框架Selenium Grid解決跨瀏覽器的兼容性問(wèn)題.
技術(shù)方案
- Python + Selenium3, 用于驅(qū)動(dòng)不同的瀏覽器執(zhí)行驗(yàn)證操作
- Selenium Grid, 用于實(shí)現(xiàn)分布式執(zhí)行用例
- VMware, 安裝不同種類(lèi)瀏覽器, 作為執(zhí)行節(jié)點(diǎn)
Selenium原理
通過(guò)Selenium控制瀏覽器模擬人工操作的過(guò)程如下:
WebDriver充當(dāng)一個(gè)HTTP Server的角色, 它接收Selenium客戶(hù)端發(fā)來(lái)的請(qǐng)求, 同時(shí)根據(jù)不同的請(qǐng)求內(nèi)容對(duì)瀏覽器進(jìn)行不同的操作.
Selenium封裝了WebDriver所能接收的各類(lèi)請(qǐng)求路由(URL)和內(nèi)容(Body)期虾,Python代碼在調(diào)用Selenium庫(kù)時(shí)其實(shí)是在操作Selenium庫(kù)發(fā)送這些HTTP請(qǐng)求妖爷。
在代碼執(zhí)行之初蔓榄,我們需要初始化一個(gè)webdriver對(duì)象,初始化的過(guò)程中浑塞,實(shí)際上是Selenium庫(kù)啟動(dòng)了一個(gè)子進(jìn)程,將WebDriver程序運(yùn)行在后臺(tái)中遭顶,監(jiān)聽(tīng)接下來(lái)Selenium客戶(hù)端發(fā)來(lái)的請(qǐng)求喇聊。
Selenium客戶(hù)端,WebDriver與瀏覽器之間通過(guò)初始化瀏覽器時(shí)生成的SessionID進(jìn)行瀏覽器對(duì)象綁定务豺,使得Python代碼能夠準(zhǔn)確的控制某一瀏覽器窗口磨总。
Selenium Grid原理
Selenium Grid 允許我們?cè)诓煌瑱C(jī)器/瀏覽器上, 同時(shí)執(zhí)行測(cè)試用例.
一個(gè)Selenium Grid結(jié)構(gòu)中包括一個(gè)主節(jié)點(diǎn)(hub)和多個(gè)從節(jié)點(diǎn)(node). 主從節(jié)點(diǎn)都是通過(guò)運(yùn)行selenium-server-standalone.jar
啟動(dòng).
Selenium 客戶(hù)端(如本項(xiàng)目)運(yùn)行在hub上, 通過(guò)Selenium Grid將操作瀏覽器的指令分發(fā)到各個(gè)node中, 即實(shí)現(xiàn)了分布式執(zhí)行測(cè)試用例.
主從結(jié)構(gòu)的優(yōu)勢(shì)在于, 無(wú)需在所有從節(jié)點(diǎn)上配置執(zhí)行環(huán)境(如Python和Selenium庫(kù)), 即可直接執(zhí)行主節(jié)點(diǎn)發(fā)來(lái)的執(zhí)行指令.
技術(shù)實(shí)現(xiàn)
自動(dòng)化測(cè)試代碼
我們可以使用各種語(yǔ)言編寫(xiě)Selenium客戶(hù)端執(zhí)行程序,因?yàn)閺腟elenium原理上可知笼沥,WebDriver本身是一個(gè)HTTP Server蚪燕,只要程序語(yǔ)言支持發(fā)送HTTP請(qǐng)求都能實(shí)現(xiàn)自動(dòng)化測(cè)試的過(guò)程。本文將使用Python編碼奔浅。
自動(dòng)化執(zhí)行過(guò)程
引用Selenium庫(kù)
Selenium的Python庫(kù)已由官方實(shí)現(xiàn)馆纳,直接安裝然后調(diào)用即可。
安裝:
pip install selenium==3.141.0
引入:
from selenium import webdriver
初始化webdriver
以Chrome瀏覽器為例:
driver = webdriver.Chrome()
我們可以打開(kāi)Chrome()
這個(gè)類(lèi)查看__init__
方法汹桦,可以看到主要過(guò)程就是設(shè)置capabilities
參數(shù)用來(lái)指定需要操作的對(duì)象是Chrome鲁驶,然后在后臺(tái)啟動(dòng)了一個(gè)子進(jìn)程(selenium/webdriver/common/service.py
中Service
類(lèi)的start
方法),這個(gè)過(guò)程與在終端中啟動(dòng)chromedriver
的效果類(lèi)似舞骆,都是啟動(dòng)了一個(gè)HTTP server钥弯,用于接收接下來(lái)的Selenium客戶(hù)端的請(qǐng)求径荔。
打開(kāi)瀏覽器
從這步開(kāi)始,代碼其實(shí)是在不斷的給WebDriver這個(gè)server發(fā)送HTTP請(qǐng)求了脆霎。
driver.get(url)
執(zhí)行成功总处,將會(huì)打開(kāi)一個(gè)瀏覽器頁(yè)面。
查找元素
查找元素的方法有很多睛蛛,這里以CSS為例鹦马,查找一個(gè)按鈕的元素ID:
element = driver.find_element_by_css_selector(submit_btn)
查找到元素后,WebDriver會(huì)返回元素的ID等信息忆肾,Selenium客戶(hù)端會(huì)創(chuàng)建一個(gè)WebElement
對(duì)象存儲(chǔ)這個(gè)元素信息荸频。
執(zhí)行點(diǎn)擊操作
WebElement
類(lèi)中包含封裝好的click卫旱,submit等多種操作棒假,許多操作過(guò)程實(shí)際是以JavaScript代碼執(zhí)行姜胖。
有了這些封裝好的方法蹬跃,執(zhí)行點(diǎn)擊某元素的操作就很簡(jiǎn)單了:
element.click()
測(cè)試結(jié)果判斷
有了自動(dòng)化執(zhí)行的過(guò)程内舟,作為自動(dòng)化測(cè)試钧惧,少不了測(cè)試的過(guò)程需五。
測(cè)試框架
測(cè)試框架可以使用Python自帶的unittest
即可讼撒,在setUp
方法中初始化瀏覽器對(duì)象燎窘,在每個(gè)測(cè)試用例中使用封裝好的斷言方法對(duì)操作的響應(yīng)進(jìn)行比較并返回結(jié)果摹闽。
更多可能性
在機(jī)器學(xué)習(xí)應(yīng)用日趨廣泛的情況下,提取預(yù)期結(jié)果的特征褐健,訓(xùn)練出符合自己業(yè)務(wù)的機(jī)器學(xué)習(xí)模型付鹿,將每次執(zhí)行操作的結(jié)果截圖作為模型輸入,可能能夠解決UI自動(dòng)化測(cè)試需要主觀判斷測(cè)試結(jié)果的難題蚜迅。
Selenium Grid分布式執(zhí)行用例
環(huán)境準(zhǔn)備
對(duì)于hub, 需要安裝:
- JDK8環(huán)境, 用于提供selenium-server-standalone.jar包的運(yùn)行環(huán)境
- selenium-server-standalone.jar, 用于建立與node的連接
- Python3環(huán)境, 用于執(zhí)行UI測(cè)試代碼
對(duì)于node, 需要安裝:
- JDK8環(huán)境, 用于提供selenium-server-standalone.jar包的運(yùn)行環(huán)境
- selenium-server-standalone.jar, 用于建立與hub的連接
- WebDriver, 用于控制瀏覽器執(zhí)行操作指令
主節(jié)點(diǎn)
- 以hub角色啟動(dòng)Selenium-server:
java -jar selenium-server-standalone-3.141.59.jar -role hub
待node節(jié)點(diǎn)連接成功后, 在hub節(jié)點(diǎn)上執(zhí)行本項(xiàng)目代碼, 即可看到node節(jié)點(diǎn)上的瀏覽器啟動(dòng)并執(zhí)行相應(yīng)操作.
從節(jié)點(diǎn)
- 以node角色啟動(dòng)Selenium-server:
java -jar selenium-server-standalone-3.141.59.jar -role node
-hub http://<IP>:4444/grid/register \
-browser "browswerName=<BrowserName>,\
version=<Version>,\
platform=<PLATFORM>"
參數(shù)說(shuō)明:
- <IP>: hub節(jié)點(diǎn)的IP, 注意hub節(jié)點(diǎn)與node節(jié)點(diǎn)需要互通, 若是虛擬機(jī), 需要將網(wǎng)絡(luò)配置為橋接(Bridge)模式
- <BrowserName>: 瀏覽器名, 如: internet explorer, chrome, firefox等
- <Version>: 瀏覽器版本號(hào): 以IE9為例, version=9
- <PLATFORM>: 系統(tǒng)類(lèi)型, 如: WINDOWS, LINUX等
在連接成功后可以看到控制臺(tái)中的一段信息:
Capabilities are: {
"browswerName": "internet explorer",
"platform": "WINDOWS",
"version":""
}
這段瀏覽器配置信息是用于Selenium客戶(hù)端連接所用:
browser = webdriver.Remote(
command_executor = 'http://localhost:4444/wd/hub',
desired_capabilities={
"browswerName": "internet explorer",
"platform": "WINDOWS",
"version":""
}
)
執(zhí)行過(guò)程
修改WebDriver入口
由于所有的瀏覽器入口都統(tǒng)一成Hub節(jié)點(diǎn)的server舵匾,因此需要將WebDriver初始化入口代碼修改。以IE為例:
driver = webdriver.Remote(
command_executor = 'http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.INTERNETEXPLORER
)
運(yùn)行
除了WebDriver入口的修改谁不,其他代碼可以基本保持不動(dòng)坐梯。
和單機(jī)的Selenium環(huán)境一樣,在Hub節(jié)點(diǎn)上直接運(yùn)行測(cè)試代碼即可刹帕,運(yùn)行后吵血,Node中可用的某個(gè)IE瀏覽器將被啟動(dòng)并執(zhí)行接下來(lái)的操作。
參考文檔
- Wire Protocol, Selenium, Github Wiki
- Selenium Grid, Selenium, Github Wiki
- Selenium with Python, Selenium, Readthedocs
- InternetExplorerDriver, Selenium, Github Wiki