Web功能性測試發表於 2012 年 3 月 15 日 由 raphaelzhang
回複
在日常工作中,我們時常需要對網站進行功能性測試,測試網站的某些功能是否正常。簡單的測試如網頁是否進行了gzip壓縮,網頁編碼是否正確,網頁載入時間是否正常,網頁緩衝時間是否正常等。複雜一點的包括網頁,網頁在載入的時候是否彈出了alert對話方塊,是否有頁面錯位或者javascript錯誤,網頁載入的資源是否是304或者200的響應等。更麻煩一點的是互動調試,調試頁面上到底是哪段javascript/CSS代碼導致了錯誤等。
簡單的Web測試
對於簡單的Web測試,例如只用查看HTTP回應標頭部與頁面內容的,只需要一個爬蟲抓取網頁,同時對頭部和內容進行分析即可。在Linux下可以使用wget和curl(它們也都有相應的Windows版本),如下:
Shell#將blog.raphaelzhang.com的頁面儲存到rz.html裡面去<br /> curl http://blog.raphaelzhang.com > rz.html</p> <p>#只查看blog.raphaelzhang.com的HTTP頭部資訊<br /> curl http://blog.raphaelzhang.com -I</p> <p>#瀏覽blog.raphaelzhang.com時帶上user-agent,referer和自訂頭部<br /> curl http://blog.raphaelzhang.com -A useragent -e http://abc.com -H "Raphael:Yes"
| 12345678 |
#將blog.raphaelzhang.com的頁面儲存到rz.html裡面去
curl http://blog.raphaelzhang.com > rz.html
#只查看blog.raphaelzhang.com的HTTP頭部資訊
curl http://blog.raphaelzhang.com -I
#瀏覽blog.raphaelzhang.com時帶上user-agent,referer和自訂頭部
curl http://blog.raphaelzhang.com -A useragent -e http://abc.com -H "Raphael:Yes" |
使用wget和curl可以下載網頁,查看HTTP頭部資訊,與awk和grep之類的工具使用,一般情況下都夠了。不過如果涉及到HTML的DOM解析之類的工作,就力不從心了。在這個時候,你可以使用喜歡的語言來開發自己的小工具,例如Python。如果是這樣的話,你可以先看看相關的注意事項。不過,你也可以使用現成的工具,例如httpie。這是一個用Python編寫的類似curl的小軟體,但是它列印出來的資訊可讀性更好,而且還有文法高亮。如果你喜歡用WSH + javascript來寫,就需要用到XmlHttpRequest組件了,其用法和普通的ajax代碼一樣簡單。
如果你不喜歡命令列程式,更喜歡互動圖形介面的話,各個瀏覽器在工具菜單下也都有相應的開發人員調試工具。第三方的工具還包括Fiddler,IETester,Firebug,以及YSlow等。
其中Fiddler最為強大,可以通過代理的方式調試所有瀏覽器的HTTP行為,包括查看時間-流量圖,本地修改javascript/CSS代碼進行互動式調試等。而IETester可以同時測試IE5.5 ~ IE10的各個IE版本,保證網頁在各版本的IE下都顯示正常。Firebug是Firefox瀏覽器的一個外掛程式,擁有極多的調試功能,查看DOM樹,查看時間-流量圖,調試javascript等。YSlow是Yahoo做的一個瀏覽器外掛程式,支援Firefox,Chrome等瀏覽器,它能對你的網頁進行檢查,並為你的網頁打分,並提出建議,以改善網頁的效能,這些建議包括對網頁進行gzip,將javascript放到尾部等。
PhantomJS測試
雖然一些簡單的測試可以通過爬蟲的方式來做,但是如果涉及到比較複雜的javascript代碼和CSS渲染的話,就必須使用真正的瀏覽器了。畢竟自己實現DOM解析還相對容易,但是如果要做javascript虛擬機器和渲染的話,工作量就太大了。
PhantomJS是一個無介面瀏覽器(Headless Browser),可以在後台運行,通過javascript代碼控制,你可以用它來做網站測試(包括自動登入,表單提交等),頁面截屏和流量監控。PhantomJS使用的是Webkit作為核心,能運行網頁裡的javascript代碼和解析CSS/HTML以渲染頁面,因此相當強大。在PhantomJS的examples目錄中有很多例子可以學習,例如產生HAR流量圖的netsniff.js等。下面是一個產生網站的例子:
JavaScript
var page = new WebPage();</p> <p>page.open(encodeURI("http://blog.raphaelzhang.com"), function (status) {<br /> if (status !== 'success') {<br /> console.log('Unable to load page!');<br /> } else {<br /> window.setTimeout(function () {<br /> page.render('snapshot.png');<br /> phantom.exit();<br /> }, 200);<br /> }<br /> });
| 123456789101112 |
var page = new WebPage();page.open(encodeURI("http://blog.raphaelzhang.com"), function (status) { if (status !== 'success') { console.log('Unable to load page!'); } else { window.setTimeout(function () { page.render('snapshot.png'); phantom.exit(); }, 200); }}); |
順便說一句,如果需要將查看HAR流量圖自動化嵌入自己網站的,網上也有開源的程式可以使用。下面是用PhantomJS做出來的流量統計資料直接得到的HAR圖。
不過PhantomJS雖好,也有幾個問題:
- 不支援對IE瀏覽器特定特性的測試,畢竟PhantomJS是基於WebKit的,因此對於特定於IE的bug是無法檢查出來的
- 不支援對彈窗的檢測,就是無法檢測網頁對
window.open的調用,,也無法有效地截獲新視窗的建立和彈出
- 無法檢測網頁上的javascript錯誤
如果要解決上述問題,就需要自己做一個基於IE(Trident)的無介面瀏覽器了,網上可以參考的代碼是CodeProject的這篇文章和SourceForge上的開源項目IECapt。
WSH javascript測試
由於我們網站90%以上的使用者用的都是IE,而有一些代碼也是特定於IE的,因此在測試的時候,必須要對IE進行自動化測試。
在Windows下進行自動化測試,自然要使用我最熟悉的WSH+javascript了,可以使用WScript對象和眾多ActiveX組件來完成諸多功能,而且文法和普通javascript都一樣,主要需要熟悉的就是各個組件的介面。
使用javascript進行IE測試的流程是:
- 通過
WScript.createObject建立一個IE對象,並綁定它的事件回調(Event Callback/Sink)
- 調用IE對象的
navigate2方法,開啟指定的網頁,並將其Visible屬性設定為true
- 在IE對象的
OnDocumentComplete事件中,檢查網頁是否已經完全載入(不然無法訪問到document對象)
- 通過document對象訪問各個HTML對象以及其計算出來的CSS屬性,並類比使用者輸入進行功能性測試
- 在最後調用IE對象的
quit方法關閉IE,如果為了保險,可以找到所有的IE視窗,向其發送Alt+F4按鍵將其關閉
- 將得到的測試資訊通過手機簡訊(如定製的HTTP介面)或者電子郵件(通過CDO.Message對象)發送到對應人員
上面是大致的流程,具體在開發過程中,還會遇到一些其他的問題:
- 在javascript中如何建立與綁定事件回調
- 如何在測試中繞過IE的阻止自動彈窗的設定,使得可以進行使用者類比點擊開啟新視窗的測試(不然彈窗會被阻止)
先說第一個問題。其實在建立一個ActiveX組件的時候,WScript.createObject方法第一個參數是組件名,第二個參數就是事件回呼函數的首碼了。例如對於IE對象來說,它的組件名是InternetExplorer.Application,對應的事件有DocumentComplete、OnQuit等(參見DWebBrowserEvents2),假設我希望收到DocumentComplete事件通知,可以這樣寫代碼:
JavaScript
var shouldQuit = false;</p> <p>function _eventsDocumentComplete(obj, url) {<br /> WScript.Echo(url);<br /> }</p> <p>function _eventsOnQuit() {<br /> shouldQuit = true;<br /> }</p> <p>var browser = WScript.createObject("InternetExplorer.Application", "_events");<br /> browser.navigate2("http://blog.raphaelzhang.com");<br /> browser.visible = true;<br /> while(!shouldQuit)<br /> {<br /> WScript.sleep(100);<br /> }
| 1234567891011121314151617 |
var shouldQuit = false;function _eventsDocumentComplete(obj, url) { WScript.Echo(url);}function _eventsOnQuit() { shouldQuit = true;}var browser = WScript.createObject("InternetExplorer.Application", "_events");browser.navigate2("http://blog.raphaelzhang.com");browser.visible = true;while(!shouldQuit){ WScript.sleep(100);} |
在上面的代碼中需要加入一個while迴圈,這樣才能不退出程式,繼而收到事件響應。
在HTML文檔都已經載入完畢以後,就可以訪問browser的document對象擷取DOM樹,進行一系列操作和測試了,例如通過document.getElementById('btnSumbit').click()類比表單提交之類的。
另外,在IE中,如果通過代碼類比點擊想產生一個新視窗,往往會被IE自動彈窗阻攔功能擋住,就是平時常見的頂部提示阻止了一個彈窗的細黃條。在測試過程中,我們往往需要類比使用者輸入產生自動彈窗,這時候,需要在測試的時候去掉這個功能,然後在測試結束的時候再開啟這個設定。要做到這一點,只需要修改註冊表的HKEY_CURRENT_USER下的\Software\Microsoft\Internet Explorer\New Windows\Allow項,添加上對應的網域名稱即可。在javascript裡可以這樣寫:
JavaScript//對host這個網域名稱允許自動彈窗<br /> var shell = WScript.CreateObject("WScript.Shell");<br /> var regKey = "HKCU\\Software\\Microsoft\\Internet Explorer\\New Windows\\Allow\\" + host;<br /> shell.RegWrite(regKey, 0, "REG_BINARY");<br /> <br /> //測試代碼<br /> //...</p> <p>//恢複自動彈窗阻止 <br /> shell.RegDelete(regKey);
| 12345678910 |
//對host這個網域名稱允許自動彈窗
var shell = WScript.CreateObject("WScript.Shell");var regKey = "HKCU\\Software\\Microsoft\\Internet Explorer\\New Windows\\Allow\\" + host;
shell.RegWrite(regKey, 0, "REG_BINARY"); //測試代碼
//...
//恢複自動彈窗阻止
shell.RegDelete(regKey); |
另外,進行IE測試需要開啟Windows案頭才行,因此它有一個比較鬱悶的要求,就是不能是未登入狀態。為瞭解決這個問題,我們開了一個Windows虛擬機器,在虛擬機器裡面專門設定了計劃任務運行這個代碼。
更多WSH + javascript開發的事情,可以參見這篇文章。在這裡有一個比較完整的WSH + javascript測試的例子,包括單元測試模板,測試頁面連結,測試彈窗與類比提交,測試結束後發送警示電子郵件等。
互動性調試
上面說的都是自動化測試,有的時候我們也需要進行互動調試,例如當頁面出現了javascript或者CSS錯誤的時候。畢竟,每次為了調試都把代碼放到vcs中,再通過cms發布出來看效果,不僅速度慢,而且也會在代碼版本中帶來無數的垃圾。
在上面我們已經提過,各個瀏覽器在工具菜單下也都有相應的開發人員調試工具,我們可以在相應的控制台下修改CSS和執行javascript代碼。在javascript代碼裡,你可以訪問和修改當前頁面的所有變數和函數,例如將某個DOM元素的onclick事件修改成你希望的樣子來調試,等等。如果javascript代碼非常簡單,也可以直接在瀏覽器的地址欄裡輸入javascript:window.alert(document.title);,以彈框顯示出當前頁面的標題。
不過對於iframe中需要訪問top視窗的javascript代碼,還有那些在頁面載入和初始化時啟動並執行代碼,上面的方法就不適用了。在這個時候,我們需要使用Fiddler,讓它在讀取相應檔案的時候就載入我們修改過的檔案。Fiddler的使用方法可以參見這裡,這裡也有一篇類似的文章。