敏捷自動化測試(2)——像用戶使用軟件同樣享受自動化測試

做者: 殷坤  來源: InfoQ jquery

  在本系列的第一篇文章「咱們的測試爲何不夠敏捷」中,根據實例總結出敏捷自動化的兩大阻礙:「腳本維護困難」、「斷言條件繁瑣」。本文針對如何下降腳本維護難度分享一些實踐經驗。 瀏覽器

  近幾年,Web技術發展勢頭迅猛,瀏覽器市場羣雄爭霸、各類UI組件庫也如雨後春筍。如今互聯網上已經不多有僅支持一種瀏覽器,而且不基於任何可複用的UI組件庫進行開發的應用了。開發人員基於各類優秀的UI組件庫(如,JQueryDojoExtJS)能夠很容易的開發出功能強大、展示絢麗、兼容各類瀏覽器的頁面(以下圖): 框架

  UI組件庫的普遍採用在提升開發效率的同時,也極大的提高了用戶體驗。基於UI組件庫之因此能快速開發出功能強大的頁面,是由於UI組件庫能夠自動生成海量、結構相似的HTML源碼(以下圖): 工具

  開發人員是幸福的,由於這一切對於他來講徹底透明。因而只剩下自動化測試人員獨自面對這樣「恐怖」的頁面源碼。 佈局

  如前文「咱們的測試爲何不夠敏捷」中所言,業界常見測試工具的腳本本質上仍是針對頁面源碼的,所以本來就舉步維艱的自動化測試在開發使用UI組件庫以後變得雪上加霜: 測試

  • 頁面DOM結構很是複雜

  致使所錄製/編寫腳本的複雜度變的更大、可讀性變得更差。 編碼

  • UI框架的升級極可能會致使DOM結構的變化

  所以即便開發人員沒對代碼作任何改動,測試腳本也會由於UI框架的升級變得沒法回放。 spa

  • 控件ID是自動生成的,甚至在每次刷新頁面後都會變化

  大部分自動化測試工具在「錄製」腳本時,都會優先使用ID定位策略,自動生成的ID會致使這種關鍵的控件定位策略變得無效。 插件

  • UI框架在各類瀏覽器下自動生成頁面源碼可能不徹底相同

  爲了在不一樣瀏覽器下「看起來同樣」,實際的DOM結構有時也多是不一樣的,所以所錄製腳本的瀏覽器兼容性會比較差。 翻譯

  技術的發展是爲了讓生活變得愈來愈輕鬆。從用戶的角度來看確實如此:Web應用的功能覆蓋範圍愈來愈廣、操做愈來愈方便、界面愈來愈美觀。

  爲何自動化測試人員沒有感受工做變得輕鬆呢?

  要回答這個問題,首先要分析「用戶使用軟件」與「自動化測試軟件」之間的一些重要差別:

  • 用戶使用軟件時只關注界面上能「看」到的,而不用老是「查看頁面源碼」;
  • 用戶會更關注總體業務的正確性、穩定性,而不只僅是每一個孤立頁面功能的正確性;
  • 用戶對頁面樣式、響應時間、瀏覽器兼容性要求愈來愈高; 若是咱們能像用戶使用軟件同樣進行自動化測試,測試就會變得更敏捷:
  • 根據界面快速編寫測試腳本:敏捷應對需求的變化;
  • 下降對技術實現(UI框架、頁面樣式/佈局)的依賴:敏捷應對設計/開發的變化;
  • 測試腳本能夠穩定支持各類瀏覽器:敏捷應對環境的變化;

  (一)根據界面快速編寫測試腳本的實現思路

  仍是之前文「咱們的測試爲何不夠敏捷」中用到的「用戶增長」界面爲例:

  若是你是做爲用戶在使用上述功能時,內心必定也會默唸下面內容吧:

  「帳號」輸入***、「密碼」輸入***、「姓名」輸入***、「性別」選擇***、「生日」輸入***、「國籍」選擇***,點擊「保存」按鈕。

  這就能夠理解爲「根據界面編寫的測試腳本」。

  咱們在使用Web應用時,內心經常默唸的還包括:「展開/收攏/選中」樹(Tree)的某個節點、數據表格(Grid)的下一頁/上一頁、選中數據表格(Grid)的某一行、點擊/關閉某個Tab頁,等等。

不少人在與筆者交流的過程當中都會問「爲何還要手工編寫腳本,怎麼不提供腳本錄製工具呢?」

所以在這裏想澄清一下你們對「編寫」腳本的誤解,與傳統自動化測試工具相比,「此腳本」非「彼腳本」。

傳統的測試腳本是給特定測試工具執行時使用的,對人類而言可讀性極差,更別談手工編寫了,所以「錄製/回放」工具每每都是必備組件。即使如此,此類「錄製/回放」工具的實際使用效果,也是不盡如人意的。

從這種角度來看,「錄製」腳本是「下策」,「上策」應該是讓測試腳本大幅簡化,而且具有良好的可讀性和可維護性,以達到人工編寫很容易的程度。

——以上只是筆者的一點差別化看法,對業界優秀的測試工具沒有任何冒犯之意!

  (二)下降測試腳本對技術實現依賴度的實現思路

  Web頁面開發中的技術實現細節主要包括UI框架的選擇及版本升級、頁面樣式設計、頁面佈局設計,所以咱們的主要目標就是下降測試腳本對這些因素的依賴。

  爲了便於測試腳本的解析和組織管理,目前還不能直接寫形如「點擊(保存)按鈕」這樣的純天然語言,但能夠設計成接近天然語言的領域專用語言(DSL:Domain Specific Language),本文采用XML來實現這種DSL。好比:

<event id="[button]保存" name="click"/>

  這種超級清晰、簡短的測試腳本與實際海量的頁面源碼之間有一條鴻溝,咱們能夠經過「封裝」來屏蔽。下面以ExtJS的Button控件爲例來示意如何完成這種封裝:

  • 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

  Firefox有不少強大插件,如Firebug、FirePath,很是有助於在開發、測試過程當中的調試問題。

  • 採用統一的UI框架開發複雜控件

  對於複雜控件,好比Tree、Grid,若是不基於統一的UI框架實現,開發、測試工做量都會很大。

  • 對於須要設置ID的控件,必定要設置惟1、而且有業務意義的ID

  固然對於通常不須要設置ID的控件(如,div)或者控件ID由UI框架自動生成的狀況除外。

  • 對於Form中最多見的label+input組合,儘可能讓label和input有邏輯對應關係

  推薦爲label設置for屬性,屬性值等於input的id,這樣對最終用戶也比較友好:雙擊label的時候,鼠標焦點能定位到對應的input中。

  • 頁面設計時考慮用戶體驗,每每用戶使用方便的時候,自動化測試也會方便

  好比,一個頁面上不要有多個同名的按鈕、經過點擊上下微調按鈕(箭頭)改變輸入域值的控件也支持直接輸入值、日期選擇控件支持用戶直接輸入、下拉列表控件支持輸入過濾,等等

  對以上幾點最佳實踐有以下補充說明:

  1. 這些最佳實踐不只能提升Web UI的可測試性,也很是有助於提高用戶體驗;
  2. 這些最佳實踐若是能知足更好,即便不能所有知足,也能夠開展自動化測試;

  按照本文給出的方案,前文「咱們的測試爲何不夠敏捷」中用到的「用戶管理(增長、刪除)」功能的自動化測試腳本就能夠改造爲以下樣式(示意代碼):

  1. <event id="[button]新增" name="click"/>
  2. <event id="[input]賬號" name="setValue" value="${account}"/>
  3. <event id="[input]密碼" name="setValue" value="1"/>
  4. <event id="[input]姓名" name="setValue" value="${accountName}"/>
  5. <event id="[input]性別" name="select" value="女"/>
  6. <event id="[input]生日" name="setDate" value="1980-01-01"/>
  7. <event id="[input ]國籍" name="select" value="中國"/>
  8. <event id="[button]保存" name="click"/>
  9. <event id="[gridRow]${account}" name="assertExist"/>
  10. <event id="[gridRow]${account}" name="check"/>
  11. <event id="[button]刪除" name="click"/>
  12. <event id="[ gridRow]${ account }" name="assertNotExist"/>

  以上測試腳本徹底基於界面上「可見」的內容進行編寫,你們應該不須要看下面的解讀,也能明白腳本的意思:

  • 第一、八、11行表示點擊「新增」、「保存」、「刪除」按鈕;
  • 第2~7行表示爲輸入域賦值,賦值方式有輸入文本、輸入日期、選擇下拉選項;
  • 第10行表示選中表格中的指定行,即,選中指定行前面的Radio按鈕;
  • 第九、12行表示斷言表格中指定的行「存在」或「不存在」;
  • ${ account }表示使用外部的變量account;

  自動化測試中最關鍵的兩部分是「腳本」和「斷言」。至此,自動化測試腳本的編寫、維護以及執行已經能夠跟上敏捷開發的步伐了。本系列的下一篇文章會就「如何讓斷言再也不成爲自動化測試的負擔」這個話題來分享一些實踐經驗,敬請關注!

相關文章
相關標籤/搜索