背景
??????項(xiàng)目是基于Ruby on Rails開發(fā)的web程序酥夭,應(yīng)該說項(xiàng)目中的測試實(shí)踐是很好的轻黑,具有高覆蓋率的單元測試以及比較合理的集成測試。存在的問題是助泽,所有的單元測試和集成測試都是針對(duì)后端代碼的啰扛,前端的JavaSript代碼沒有單元測試(這個(gè)是有歷史原因的,暫時(shí)沒法改變)报咳。這也就意味著針對(duì)前端UI的修改是沒有底層的單元測試來保障的侠讯,只能依靠高層級(jí)的UI自動(dòng)化測試和手工測試來保障。
??????我們最近剛剛完成了一個(gè)story暑刃,是純前端的開發(fā)工作厢漩,結(jié)果在上線后發(fā)現(xiàn)我們?cè)谛薷捻撁婺0逦募r(shí),忘記了其他地方也在使用同樣的模板文件岩臣,導(dǎo)致了部分頁面樣式錯(cuò)亂溜嗜,甚至無法訪問宵膨。這個(gè)bug在現(xiàn)有的UI自動(dòng)化測試和手工測試中都被遺漏了,直接發(fā)布到了產(chǎn)品環(huán)境上炸宵,后來通過線上日志才被發(fā)現(xiàn)辟躏。不得已我們只好把版本先回退,修復(fù)bug后再重新上線土全,release的時(shí)間推遲了一周捎琐,可以說整個(gè)團(tuán)隊(duì)為此付出了嚴(yán)重的代價(jià)。
痛點(diǎn)
? ? ??作為團(tuán)隊(duì)的QA裹匙,出現(xiàn)這樣的問題自然讓我很不好受瑞凑,顏面無光。概页。籽御。拋開沒有做story業(yè)務(wù)分析,手工測試場景遺漏等問題惰匙,聚焦在現(xiàn)有的UI自動(dòng)化測試上技掏,以下是我感知到的一些痛點(diǎn):
UI自動(dòng)化測試的穩(wěn)定性不高 - UI自動(dòng)化測試是用ruby版本的selenium實(shí)現(xiàn)的,存在著眾所周知的問題项鬼,例如不夠穩(wěn)定哑梳,經(jīng)常由于頁面加載超時(shí),UI交互復(fù)雜等問題導(dǎo)致測試失敗秃臣,使得自動(dòng)化測試結(jié)果的有效性不高涧衙,失去了它本來應(yīng)該具有的價(jià)值。
測試場景覆蓋不夠全面 - 當(dāng)然奥此,根據(jù)測試金字塔的理念,上層的UI自動(dòng)化測試應(yīng)該是小規(guī)模的雁比,只覆蓋基本功能:
??????但是具體到這個(gè)項(xiàng)目中稚虎,由于前端代碼的底層測試缺失,所以不得不依靠高層級(jí)的UI自動(dòng)化測試來覆蓋更多的場景偎捎, ? 最起碼要能完成基本的回歸測試蠢终,否則手工測試的壓力太大。這就回到了第一個(gè)問題茴她,正是由于UI自動(dòng)化測試的穩(wěn)定性不高寻拂,所以我只實(shí)現(xiàn)了很小一部分功能,以免后續(xù)維護(hù)的成本太高丈牢,而我們遺漏的bug恰恰沒有包含在自動(dòng)化測試的場景中祭钉。
問題分析
? ? ??所以,我們的聚焦點(diǎn)集中在了如何提高UI自動(dòng)化測試的質(zhì)量上己沛,經(jīng)過分析慌核,主要的問題有:
頁面加載時(shí)間超時(shí)
在用webdriver的方法訪問頁面時(shí)距境,經(jīng)常出現(xiàn)加載超時(shí)的問題。頁面的DOM結(jié)構(gòu)已經(jīng)渲染完成了垮卓,但是在訪問某些外部網(wǎng)站時(shí)長時(shí)間沒有響應(yīng)垫桂,導(dǎo)致測試腳本一直卡著無法繼續(xù)進(jìn)行,最后報(bào)超時(shí)錯(cuò)誤粟按。
頁面交互action太多
UI自動(dòng)化測試的一個(gè)缺點(diǎn)就是所有的執(zhí)行動(dòng)作都要通過頁面的action來完成诬滩,例如文本框輸入,點(diǎn)擊按鈕灭将,而且這些動(dòng)作的執(zhí)行結(jié)果存在太多的變數(shù)疼鸟,導(dǎo)致最后寫出來的測試腳本太過脆弱,很容易失敗宗侦。
解決問題
使用異常捕獲機(jī)制來處理超時(shí)等異常情況
??????針對(duì)頁面超時(shí)的問題愚臀,由于頁面的DOM結(jié)構(gòu)已經(jīng)渲染完成了,所以其實(shí)可以繼續(xù)執(zhí)行后續(xù)的用例矾利。但是如果與外部網(wǎng)站的請(qǐng)求沒有全部完成姑裂,selenium會(huì)認(rèn)為頁面加載沒有完成,就一直卡在訪問頁面的get方法上男旗。我的做法是設(shè)定一個(gè)頁面加載的超時(shí)時(shí)間:
dr.manage.timeouts.page_load = 30
??????超過30秒就認(rèn)為頁面加載超時(shí)(經(jīng)過測試舶斧,30秒的時(shí)間已經(jīng)足夠把頁面的DOM結(jié)構(gòu)渲染完成了),然后訪問頁面時(shí)捕獲超時(shí)的異常:
begin
? ?page.open_page
rescue Selenium::WebDriver::Error::TimeOutError
???puts "ERROR:page load timeout!!"
end
??????這樣如果加載超過30秒察皇,會(huì)拋出異常后繼續(xù)向下執(zhí)行茴厉。不致于因?yàn)樵L問某些外部網(wǎng)站請(qǐng)求過慢,而卡在頁面加載的步驟什荣,導(dǎo)致整個(gè)測試用例失敗矾缓。同樣的策略也可以應(yīng)用在某些復(fù)雜或者不確定的執(zhí)行結(jié)果上,捕獲可能出現(xiàn)的異常稻爬,提高測試的健壯性嗜闻,避免非產(chǎn)品原因?qū)е碌臏y試用例失敗。
減少UI測試桅锄,增加API級(jí)別的測試
這個(gè)觀點(diǎn)聽上去多少有點(diǎn)荒唐琉雳,提高UI測試質(zhì)量的方法是減少UI測試。友瘤。翠肘。。但事實(shí)就是這樣辫秧,UI測試是自動(dòng)化成本最高束倍,最不穩(wěn)定的測試,能夠在低層級(jí)完成的測試,例如API層的測試肌幽,就不要放到UI層去完成晚碾,這樣會(huì)使測試更加穩(wěn)定和健壯。很多頁面action喂急,例如提交表單格嘁,點(diǎn)擊按鈕等,實(shí)際都是向后臺(tái)發(fā)送了一條請(qǐng)求廊移,如果測試的是功能糕簿,那么完全可以用API來完成這些測試。重點(diǎn)還是在于我們究竟想測什么狡孔,是否必須要從UI層去完成這些測試懂诗?這就是測試結(jié)構(gòu)的設(shè)計(jì)問題了,這里不展開討論苗膝。
在這個(gè)項(xiàng)目中殃恒,我把一些可以在API層完成的測試從UI測試用例中分離出來,用ruby的Faraday庫(當(dāng)然也可以用其他的辱揭,例如JS的SuperTest)調(diào)用相應(yīng)的API并對(duì)返回?cái)?shù)據(jù)做校驗(yàn)离唐,這些測試相比于UI測試更加穩(wěn)定,運(yùn)行速度更快问窃,整個(gè)測試的穩(wěn)定性便得到了提升亥鬓。
將頁面交互的action與靜態(tài)頁面內(nèi)容分開測試
這個(gè)方法的思路和上一個(gè)類似,盡量減少通過頁面加載和交互來完成的測試域庇。如果測試內(nèi)容中不包含動(dòng)態(tài)的頁面交互步驟嵌戈,例如只是想測試頁面能否正常打開,某一部分的內(nèi)容能否正常顯示等听皿,可以從頁面的DOM結(jié)構(gòu)中通過校驗(yàn)?zāi)承┰貋硗瓿蓽y試熟呛。
舉個(gè)例子,如果想測試百度首頁尉姨,可以不用從selenium webdriver中去加載這個(gè)頁面惰拱,直接用ruby的Faraday或者JS的SuperTest去訪問"http://www.baidu.com"這個(gè)URL。這樣拿到的將是一段html的文本啊送,然后再解析這段html文本(例如用ruby的Nokogirl庫),獲取對(duì)應(yīng)的內(nèi)容來做校驗(yàn)欣孤。例如返回碼是200馋没,<title>的內(nèi)容是“百度一下,你就知道”,那么可以認(rèn)為首頁能夠正常打開。<img>中的src屬性是一個(gè)正確的圖片文件虽风,可以認(rèn)為百度的logo能夠正常顯示橄碾。
這里會(huì)產(chǎn)生疑問膘掰,如果我就是想測試界面怎么辦尺锚?這就回到了剛才那個(gè)問題席楚,我們究竟想測什么趣惠?如果只是想測功能腮猖,那么我們就盡量減少對(duì)界面的依賴鉴扫。如果只是想測界面,那么也有其他的辦法來完成澈缺,例如WebdriverCSS或者PhantomCSS等界面對(duì)比的測試工具坪创。當(dāng)然,有些測試步驟是必須要依賴頁面交互的姐赡,例如點(diǎn)擊某個(gè)按鈕打開一個(gè)新的對(duì)話框或者跳轉(zhuǎn)到其他頁面莱预,這些測試就只能通過webdriver來完成了。
總結(jié)
??????通過實(shí)際的嘗試项滑,我明顯感覺到優(yōu)化后的自動(dòng)化測試相比于原來有了更穩(wěn)定的表現(xiàn)依沮,運(yùn)行速度變快,非產(chǎn)品原因?qū)е碌挠美〈螖?shù)變少枪狂。而且自動(dòng)化測試更穩(wěn)定后危喉,我有信心去實(shí)現(xiàn)更多的自動(dòng)化測試,擴(kuò)大覆蓋的場景摘完。我的一些感受和收獲是:
1.UI自動(dòng)化測試的編碼實(shí)現(xiàn)不難姥饰,難的是如何做整體的測試結(jié)構(gòu)設(shè)計(jì)。在UI測試中覆蓋的場景太少達(dá)不到測試的目的孝治,場景太多又會(huì)成為團(tuán)隊(duì)的負(fù)擔(dān)列粪,帶來高昂的維護(hù)成本,需要和UT/API等測試綜合考慮谈飒,互相彌補(bǔ)岂座。
2.UI自動(dòng)化測試是把雙刃劍,它應(yīng)該是QA最后考慮的自動(dòng)化測試方法杭措。只有當(dāng)其他層級(jí)的測試無法達(dá)到目的费什,或者希望測試的內(nèi)容必須要通過UI完成時(shí),再去考慮用它手素。低層級(jí)能完成的測試不要放在高層級(jí)去完成鸳址,在靜態(tài)DOM結(jié)構(gòu)中能完成的測試不要通過webdriver加載頁面去完成。