問題描述
本文的標題看起來有些含糊其辭,這里我需要把問題闡述得更加清楚。這是我們使用VSTS進行Web Performance Test時,Asp.net造成的特定問題(也許其他開發工具或插件也會造成類似問題)。 我們知道Asp.net的控件名在前端是自動生成的,比如開發人員設計時,控件名為username; 在bowser端,會自動生成包含一大段前綴的HTML控件,例如ctl00$content$SiteThemeContentPage1$fragment_3526$ctl01$ctl00$LoginForm1$ctl07$username。具體的生成機制我沒有研究,但是這個控件名的前綴確實是會隨着比如父控件名,重新編譯的變化而變化。
對於我們Web Performance Test來說,問題在哪里呢? 比如我們錄制了一個Post Request,來模擬一個Form PostBack(見Asp.net的知識),如下圖所示:
Post的參數名中包含了這些帶着自動生成的前綴的控件名。以下兩種情況對測試用例的維護非常糟糕:
1,隨着編譯生成的前綴的變化,每隔一段時間,我們就需要更新Post Request中的參數名,來避免測試失敗,如果你有大量的測試用例,或者用例中有大量PostBack的控件(Asp.net中這很常見),這個工作讓人發狂。
2,項目可能部署了好幾個測試版本需要進行load test,那么你就要維護好幾個版本的測試用例,再考慮到第一條,這簡直不是人干的了。
解決方案
如果是進行Web的UI測試,顯然我們已經很多種辦法來應付這種情況(雖然Web UI測試本質上和Web Performance測試是不同的,Web Performance測試是直接運行在HTTP層的,但是還是有很多東西可以借鑒);比如Selenium2 我們可以用XPath,css selector來定位控件,TestComplete可以使用Name Mapping;正如我們標題所說的,我們將用XPath的方式,比如上文中的username控件,我們用這樣的語法來匹配控件名 -- "//text[contains(@name,'username')]"。 但是Web Performance Test原生不支持XPath,而這就是我們要做的。具體應該怎么做呢? 這里我不打算直接貼出代碼了,而是給出主要的步驟:
1,我們應該添加一個WebTestPlugin。為什么不是Custom Extraction Rule呢?因為我們這里需要抽取的並不是Post參數的值,而是Post參數名,考慮一下其中的區別。(是的,寫一個Custom Extraction Rule,通過Xpath來抽取Content Parameter是一個非常好的實踐,網上已經有相關的文章了,但是本文講述的是另一個問題)
2,采用HtmlAgilityPack來支持XPATH語法。這是一個為HTML提供XPATH支持的開源庫,在我用來還不錯,這里下載。當然你可以使用其他的庫。
3,我們可以定義這樣的語法,如下圖所示:
前綴"XPath:",后面接XPath的匹配字符串。今后我們也可以添加更多的前綴支持,如"CssSelector:",然后根據不同的前綴,路由到不同的處理函數中
4,寫一個自定義的WebTestPlugin。很明顯,我們需要重寫PreRequest函數,它需要做的是:
1) 遍歷e.Request.Body中FormPostParameters,也就是所有的Post參數。找到參數名包含前綴XPATH:的參數,把xpath匹配符從參數名中提取出來。
2) 通過e.WebTest.LastResponse.BodyString,獲取HTML文本。創建HtmlAgilityPack的HtmlDocument對象。用步驟1種得到的xpath進行查詢,找到控件。
3) 用步驟2中得到的真實的控件名,也就是ctl00$content$SiteThemeContentPage1$fragment_3526$ctl01$ctl00$LoginForm1$ctl07$username。來替換FormPostParameter對象中原來的的控件名,也就是匹配符XPath://input[contains(@name,’username’)],大功告成。
Binhua Liu原創,2013/10/5