做者: 殷坤 來源: InfoQ jquery
在本系列的第一篇文章「咱們的測試爲何不夠敏捷」中,根據實例總結出敏捷自動化的兩大阻礙:「腳本維護困難」、「斷言條件繁瑣」。本文針對如何下降腳本維護難度分享一些實踐經驗。 瀏覽器
近幾年,Web技術發展勢頭迅猛,瀏覽器市場羣雄爭霸、各類UI組件庫也如雨後春筍。如今互聯網上已經不多有僅支持一種瀏覽器,而且不基於任何可複用的UI組件庫進行開發的應用了。開發人員基於各類優秀的UI組件庫(如,JQuery、Dojo、ExtJS)能夠很容易的開發出功能強大、展示絢麗、兼容各類瀏覽器的頁面(以下圖): 框架
UI組件庫的普遍採用在提升開發效率的同時,也極大的提高了用戶體驗。基於UI組件庫之因此能快速開發出功能強大的頁面,是由於UI組件庫能夠自動生成海量、結構相似的HTML源碼(以下圖): 工具
開發人員是幸福的,由於這一切對於他來講徹底透明。因而只剩下自動化測試人員獨自面對這樣「恐怖」的頁面源碼。 佈局
如前文「咱們的測試爲何不夠敏捷」中所言,業界常見測試工具的腳本本質上仍是針對頁面源碼的,所以本來就舉步維艱的自動化測試在開發使用UI組件庫以後變得雪上加霜: 測試
致使所錄製/編寫腳本的複雜度變的更大、可讀性變得更差。 編碼
所以即便開發人員沒對代碼作任何改動,測試腳本也會由於UI框架的升級變得沒法回放。 spa
大部分自動化測試工具在「錄製」腳本時,都會優先使用ID定位策略,自動生成的ID會致使這種關鍵的控件定位策略變得無效。 插件
爲了在不一樣瀏覽器下「看起來同樣」,實際的DOM結構有時也多是不一樣的,所以所錄製腳本的瀏覽器兼容性會比較差。 翻譯
技術的發展是爲了讓生活變得愈來愈輕鬆。從用戶的角度來看確實如此:Web應用的功能覆蓋範圍愈來愈廣、操做愈來愈方便、界面愈來愈美觀。
爲何自動化測試人員沒有感受工做變得輕鬆呢?
要回答這個問題,首先要分析「用戶使用軟件」與「自動化測試軟件」之間的一些重要差別:
仍是之前文「咱們的測試爲何不夠敏捷」中用到的「用戶增長」界面爲例:
若是你是做爲用戶在使用上述功能時,內心必定也會默唸下面內容吧:
「帳號」輸入***、「密碼」輸入***、「姓名」輸入***、「性別」選擇***、「生日」輸入***、「國籍」選擇***,點擊「保存」按鈕。
這就能夠理解爲「根據界面編寫的測試腳本」。
咱們在使用Web應用時,內心經常默唸的還包括:「展開/收攏/選中」樹(Tree)的某個節點、數據表格(Grid)的下一頁/上一頁、選中數據表格(Grid)的某一行、點擊/關閉某個Tab頁,等等。
不少人在與筆者交流的過程當中都會問「爲何還要手工編寫腳本,怎麼不提供腳本錄製工具呢?」
所以在這裏想澄清一下你們對「編寫」腳本的誤解,與傳統自動化測試工具相比,「此腳本」非「彼腳本」。
傳統的測試腳本是給特定測試工具執行時使用的,對人類而言可讀性極差,更別談手工編寫了,所以「錄製/回放」工具每每都是必備組件。即使如此,此類「錄製/回放」工具的實際使用效果,也是不盡如人意的。
從這種角度來看,「錄製」腳本是「下策」,「上策」應該是讓測試腳本大幅簡化,而且具有良好的可讀性和可維護性,以達到人工編寫很容易的程度。
——以上只是筆者的一點差別化看法,對業界優秀的測試工具沒有任何冒犯之意!
Web頁面開發中的技術實現細節主要包括UI框架的選擇及版本升級、頁面樣式設計、頁面佈局設計,所以咱們的主要目標就是下降測試腳本對這些因素的依賴。
爲了便於測試腳本的解析和組織管理,目前還不能直接寫形如「點擊(保存)按鈕」這樣的純天然語言,但能夠設計成接近天然語言的領域專用語言(DSL:Domain Specific Language),本文采用XML來實現這種DSL。好比:
<event id="[button]保存" name="click"/>
這種超級清晰、簡短的測試腳本與實際海量的頁面源碼之間有一條鴻溝,咱們能夠經過「封裝」來屏蔽。下面以ExtJS的Button控件爲例來示意如何完成這種封裝:
實際生成的頁面源碼DOM結構以下(省略部分非關鍵屬性):
<div id="button-1032" class="x-btn x-box-item x-btn-default-small x-noicon x-btn-noicon > <em id="button-1032-btnWrap"> <button id="button-1032-btnEl" class="x-btn-center" autocomplete="off" role="button"> <span id="button-1032-btnInnerEl">Cancel <span id="button-1032-btnIconEl" class="x-btn-icon "/> </button> </em> </div>
咱們封裝所要作的主要工做就是解析出測試腳本中定義的關鍵信息(button、保存、click),結合對應頁面源碼的DOM結構,翻譯成W3C標準的定位方式(如,XPath)。經過XPath就能夠定位到頁面上的任何控件。
對於測試腳本(<event id="[button]Cancel" name="click"/>),翻譯後的XPath能夠是(//button/span[text()='Cancel'])。
同理,其它測試腳本還能夠包括:
- 樹節點展開/關閉
<event id="[treeNode]部門" name="open"/><event id="[treeNode]部門" name="close"/>
- Grid翻頁
<event id="[grid]人員列表" name="nextPage"/>
它們的封裝實現比Button稍微複雜一些,但原理是同樣的。
這個就比較簡單了,只要選用標準化程度高、廠商支持度高、擴展性強的第三方底層實現便可,筆者推薦採用Selenium WebDriver。
經過上面的介紹,有些讀者或許會有個疑問:「若是一個Web應用沒有采用任何UI框架、並且編碼又極爲不規範,那麼你這種方案豈不就不適用了?」
答案是確定的。但筆者認爲此類Web應用若是想要發展下去,其瓶頸還停留在開發環節,對其進行自動化迴歸測試的投入產出比不是很大。
此外,爲了進一步提升Web應用的可測試性,筆者在實際工做中總結了一些前臺頁面開發的最佳實踐,供你們參考:
若是頁面上的frame/iframe嵌套不少的話,控件的定位會比較麻煩,而且影響展示速度。
Firefox有不少強大插件,如Firebug、FirePath,很是有助於在開發、測試過程當中的調試問題。
對於複雜控件,好比Tree、Grid,若是不基於統一的UI框架實現,開發、測試工做量都會很大。
固然對於通常不須要設置ID的控件(如,div)或者控件ID由UI框架自動生成的狀況除外。
推薦爲label設置for屬性,屬性值等於input的id,這樣對最終用戶也比較友好:雙擊label的時候,鼠標焦點能定位到對應的input中。
好比,一個頁面上不要有多個同名的按鈕、經過點擊上下微調按鈕(箭頭)改變輸入域值的控件也支持直接輸入值、日期選擇控件支持用戶直接輸入、下拉列表控件支持輸入過濾,等等
對以上幾點最佳實踐有以下補充說明:
按照本文給出的方案,前文「咱們的測試爲何不夠敏捷」中用到的「用戶管理(增長、刪除)」功能的自動化測試腳本就能夠改造爲以下樣式(示意代碼):
- <event id="[button]新增" name="click"/>
- <event id="[input]賬號" name="setValue" value="${account}"/>
- <event id="[input]密碼" name="setValue" value="1"/>
- <event id="[input]姓名" name="setValue" value="${accountName}"/>
- <event id="[input]性別" name="select" value="女"/>
- <event id="[input]生日" name="setDate" value="1980-01-01"/>
- <event id="[input ]國籍" name="select" value="中國"/>
- <event id="[button]保存" name="click"/>
- <event id="[gridRow]${account}" name="assertExist"/>
- <event id="[gridRow]${account}" name="check"/>
- <event id="[button]刪除" name="click"/>
- <event id="[ gridRow]${ account }" name="assertNotExist"/>
以上測試腳本徹底基於界面上「可見」的內容進行編寫,你們應該不須要看下面的解讀,也能明白腳本的意思:
自動化測試中最關鍵的兩部分是「腳本」和「斷言」。至此,自動化測試腳本的編寫、維護以及執行已經能夠跟上敏捷開發的步伐了。本系列的下一篇文章會就「如何讓斷言再也不成爲自動化測試的負擔」這個話題來分享一些實踐經驗,敬請關注!