敏捷自動化測試(1) —— 咱們的測試爲何不夠敏捷?

    做者: 殷坤  來源: InfoQ html

 測試是爲了保證軟件的質量,敏捷測試關鍵是保證能夠持續、及時的對軟件質量狀況進行全面的反饋。因爲在敏捷開發過程當中每一個迭代都會增長功能、修復缺陷或重構代碼,因此在完成當前迭代新增特性測試工做的同時,還要經過迴歸測試來保證歷史功能不受影響。爲此咱們指望: web

  測試範圍足夠廣: 編程

  • 測試用例要覆蓋全部功能;
  • 要在各類可能的環境下做兼容性測試;
  • 系統的穩定性、性能都要測試;

  測試頻率足夠高: 瀏覽器

  • 每日構建產生的版本要保證可用;
  • 每一個迭代都須要對歷史功能作迴歸測試;
  • 釋放前或上線後若是打了補丁,就須要迴歸;

  但實際狀況每每不遂人願: 併發

  實際測試周期變短: 框架

  • 上線時間提早肯定,研發進度延期,測試計劃被迫延後;
  • 最後階段常常會臨時增長測試任務;
  • 全部人都知道還須要再通過一輪測試,但時間沒有了;

  有效測試資源稀缺: 編程語言

  • 臨時從其餘項目抽調的測試人員不能馬上有效的開展測試工做;
  • 「搞不清楚」本項目的研發人員究竟是不會作測試仍是不肯作測試;

  所以因爲客觀上的資源和時間限制,完整的、及時迴歸測試在人工測試狀況下,每每是不可能完成的任務。團隊內部也會產生各類爭執: 函數

  • 提交給測試的版本爲何研發人員不先作經過性測試?
  • 此次代碼改動量不大,有必要再花那麼多時間迴歸麼?
  • 當初不是承諾此次修改確定不會影響之前的功能麼?
  • 怎麼不早說要支持Chrome瀏覽器,如今哪還有時間測試啊?
  • 怎麼能讓現場出現這種低級的Bug,打補丁後爲何不仔細迴歸一遍?

  爭執越演越烈,最終有團隊成員爆發了:「這簡直不是人乾的活!」。 工具

  您怎麼看待這句話呢? 佈局

  其實話糙理不糙,用更理性的語言翻譯一下就是「有些工做不該該以人工的方式來完成」,好比:

  • 大量機械的、重複性的迴歸測試;
  • 結果的正確性不依賴主觀判斷的測試;
  • 須要模擬大量數據、大量併發量的測試;
  • 須要不間斷執行的測試(好比7*24小時持續執行);
  • 須要短期內完成的大量測試用例執行(好比完整的功能迴歸測試);

  經過自動化測試能夠極大的提高迴歸測試、穩定性測試以及兼容性測試的工做效率,在保障產品質量和持續構建等方面起到舉足輕重的做用。特別是在敏捷開發模式下,自動化測試是必不可少的。

  目前業界的商業/開源自動化測試工具備不少,好比,功能測試工具備QTP、Selenium等,性能測試有LoadRunner、JMeter等。其工做原理無非都是經過「測試腳本」和「測試數據」來完成「測試過程」,並比較「測試結果」,進而造成「測試報告」。

  本文不對這些測試工具的差別或優劣進行對比,只以做者目前採用的Selenium爲例進行分析:敏捷開發模式須要自動化測試,但自動化測試自己的敏捷性又如何呢?

  Selenium是針對Web應用的開源自動化測試工具,經過編寫模擬用戶操做的腳本,它會打開瀏覽器對Web應用進行黑盒測試。能夠方便的用於功能測試、兼容性測試、 穩定性測試及併發測試。目前已被主流瀏覽器廠商普遍支持,同時也是不少其它自動化測試工具(好比,RobotFramework)的底層核心技術。Selenium由IDE、Remote Control(簡稱RC)、WebDriver、Grid四個工程組成:

  • Selenium IDE

  是一個用於錄製/回放測試腳本的Firefox附加組件,錄製的腳本能夠生成基於Selenium RC的測試代碼(Java、Ruby、C#等)。適用於快速入門,不太適用於實際較大的測試項目;

  • Selenium RC

  RC由Server和Client組成兩部分組成,Server負責加載/關閉瀏覽器以及做爲HTTP代理來訪問Web應用,Clinet支持多種編程語言和測試框架(TestNG、JUnit、NUnit等)。

  • Selenium WebDriver

  WebDriver做爲Selenium2的核心特性提供比RC更簡潔易用的API,是官方推薦的RC替代方案。能夠更好的支持動態網頁,不須要再額外啓動一個獨立的Server。

  • Selenium Grid

  是Selenium的一個擴展工具,能夠很方便地同時在多臺機器上和異構環境中並行運行多個RC或WebDriver用例。

  Selenium RC是經過在瀏覽器加載時「注入」JS函數來操縱後續的瀏覽器行爲,Selenium WebDriver則經過直接調用各個瀏覽器內置的本地事件來達到這一目的。WebDriver目前已經做爲W3C規範草案,提交由Google、Mozilla等瀏覽器廠商討論。

WebDriver規範定義一組與平臺、語言無關的接口,包括髮現和操做頁面上的元素以及控制瀏覽器行爲,主要用於支持Web應用的自動化測試。 WebDriver的核心是經過findElement方法返回DOM對象(WebElement),經過WebElement能夠對DOM對象進行操做 (獲取屬性、觸發事件等)。其中findElement方法須要的元素定位器(Locator)支持ID、XPath、CSS、超連接文本等多種方式。

  「WebDriver」顧名思義就是「Web瀏覽器驅動」,它專一於解決如何經過外部命令(一般爲測試用例)操做瀏覽器的問題。至於測試用例按照什麼順序執行、執行過程當中如何傳遞數據、測試結果如何斷言、如何報告,則能夠經過集成其它優秀的專業測試框架(好比,TestNG)來實現(WebDriver沒有必要重複造輪子)。

  下面用以「用戶管理」爲例,來看看用WebDriver實現的「增長」和「刪除」測試腳本(只示意部分關鍵代碼)。

  一、在用戶列表頁面點擊「新增」按鈕,跳轉到新增用戶頁面:

webDriver.findElement(By.xpath("//a[contains(@id,'addUserBtn')]//button")).click();.

  腳本解讀:

  • By.xpath()表示經過XPath來定位頁面元素;
  • click()表示在找到的當前控件上執行點擊操做;

  二、在新增用戶頁面,輸入「賬號」、「密碼」、「姓名」,選擇「性別」、「生日」和「國籍」,而後點擊「保存」按鈕,回到用戶列表頁面,並判斷是否增長成功:

1)  String account="autotest2";  2)  webDriver.findElement(By.xpath("//div[contains(@id,'account_userForm')]//input")).sendKeys(account); 3)  webDriver.findElement(By.xpath("//div[contains(@id,'password_userForm')]//input")).sendKeys("1");  4)  webDriver.findElement(By.xpath("//div[contains(@id,'name_userForm')]//input")).sendKeys(account);  5)  webDriver.findElement(By.xpath("//div[contains(@id,'sex_userForm')]//input")).click();  6)  webDriver.findElement(By.xpath("//span[text()='女']")).click();  7)  webDriver.findElement(By.xpath("//div[contains(@id,'birthdate_userForm')]//input")).click();  8)  webDriver.findElement(By.xpath("//div[contains(@id,'nationality_userForm')]//input")).click();  9)  webDriver.findElement(By.xpath("//span[text()='中國']")).click();  10) webDriver.findElement(By.xpath("//a[contains(@id,'userSaveBtn')]//button")).click();  11) WebElement ele = webDriver.findElement(By.xpath("//div[text()='"+account+"']")); 12) Assert.assertNotNull(ele);

  腳本解讀:

  • sendKeys ()表示在找到的當前控件上輸入字符;
  • 2~9行表示經過輸入或點擊選擇的方式爲用戶相關屬性賦值;
  • 第10行表示點擊「保存」按鈕(點擊後會自動轉向用戶列表頁面);
  • 11~12行表示查找頁面上文本內容爲新增賬號的div,並斷言該div是存在的(不爲空);

  三、刪除剛剛增長的人員,而後判斷是否刪除成功:

1)  webDriver.findElement(By.xpath("//a[contains(@id,'deleteUserBtn')]//button")).click();  2)  WebElement ele = webDriver.findElement(By.xpath("//div[text()='"+account+"']"));  3)  Assert.assertNull(ele);

  腳本解讀:

  • 第1行表示點擊「刪除」按鈕;
  • 2~3行表示查找頁面上文本內容爲新增賬號的div,並斷言該div已經不存在了(爲空);

  經過上面的腳本就能夠實現「用戶增長、刪除」的自動化測試,而且能夠跨瀏覽器。看到這裏您會不會以爲總體還不錯,若是測試腳本再能經過錄制的方式自動生成就更好了!

  「看」起來確實還不錯,但在實際項目中用起來就沒那麼爽了。這實際上是在技術/工具選型時廣泛存在的現象:在驗證/試用階段的評價很高,但在投入生產使用時會遇到各類各樣的問題,所以你們在選型階段除了考慮功能,還要考慮技術/工具自己的開放性和可擴展性。

  上面的方案單純從技術的角度來說是很不錯的:開源、社區活躍、標準化程度高、支持跨瀏覽器、腳本回放穩定、可集成性高,等等。

  可是若是就這樣應用在實際項目中,會從過程的角度暴露一些棘手的問題:

  • 測試腳本是「代碼級」的,那麼應該由誰來編寫呢?

  測試人員和開發人員好像都有編寫這些測試腳本義務,但彷佛又都有不寫的理由。

  • 測試腳本必須不斷的修改才能在最新版本上跑通,誰該爲此買單?

  在敏捷開發過程當中須要快速響應需求的變化(新增、變動),這一點整個團隊都好理解。所以若是需求發生變化,開發人員修改代碼、測試人員修改測試 腳本,一切瓜熟蒂落,你們相安無事。可是在用戶需求沒有變化時,開發人員頻繁修改代碼的狀況也很常見:好比,修改Bug、針對「壞味道」作重構、調整頁面 佈局或樣式。因而在「毫無徵兆」的狀況下,測試腳本又沒法執行了!

  這時候測試人員可能會質問開發人員:「作以前怎麼不想清楚?都已經測試完成的功能,爲何還老是反覆修改?何時代碼才能穩定?」。

  而開發人員此時也會很是義正詞嚴:「有Bug能不改麼?頁面佈局不合理致使用戶體驗差,能不改麼?並且敏捷中的一個重要的實踐就是重構啊」。

  你們又是彷佛都有道理、也都有苦衷。我雖然做爲測試人員,可是在這個問題上仍是「偏向於」開發人員的: 在軟件生命週期的各個階段(需求、設計、開發、測試)中,後面的階段對前置階段是有必定依賴的,因此越日後期響應變化的難度越大。好比,在「開發」環節不 僅須要響應「需求」的變化(新增、變動),並且須要響應「設計」的變化。從這個角度來看,「測試」本就應該響應「開發」的變化。

  對於在實際項目自動化測試過程當中遇到的上述問題,歸根究竟是由於「自動化測試方案自己的敏捷程度不夠」,主要體如今以下三個方面:

  一、 學習成本高

  測試人員除了要掌握WebDriver接口以外,還要掌握XPath、TestNG的用法,甚至還須要對功能的前臺實現有必定了解。

  二、 腳本維護困難

  敏銳的開發/測試人員從上面的示例腳本中,能夠立刻嗅出一些「壞味道(Bad Smell)」: 代碼類似度很是高、可能變化的數據被硬編碼在測試代碼裏、代碼可讀性差、測試代碼與頁面源碼耦合度大,等等。這些壞味道的出現,一般意味着須要進行重構, 不然會愈演愈烈,最終變得尾大不掉。

  【注】業界常見的測試工具本質上仍是針對頁面源碼來編寫(或生成)測試腳本的,即便提供了錄製工具,此類腳本的可讀性和後期可維護性仍是很是差的。

  三、 斷言條件繁瑣

  業界常見的測試工具即便提供錄製腳本的功能,可是對於「斷言」仍是須要人工插入的(工具作不到智能的判斷咱們想要在哪裏設置斷言),因而斷言就成了自動化測試人員的「噩夢」。

  斷言對象可能很「多」,頁面的信息量每每很大,須要在測試腳本中爲每一個斷言對象(好比,頁面某個文本框的值)補充斷言語句。

  預期結果是可能「變」化的,甚至是動態的,所以預期結果的值若是與腳本邏輯耦合在一塊兒,未來極難維護。 斷言機制比較「呆」板,對於 未設爲斷言對象的字段,若是發生錯誤也是沒法感知的,而且難以對於UI樣式或UI邏輯(好比,翻頁圖標應該灰顯)進行斷言。

  換個角度能夠理解爲,若是這樣的斷言條件「多」的話,整個測試用例集會「變」的很是「呆」板!

  想要有效的改善這些問題,就必須讓自動化測試變得「敏捷」起來!

  在本系列後續的文章中會就「如何讓測試腳本易寫、易讀、易維護」、「如何讓斷言再也不成爲測試的負擔」、「如何經過持續集成讓測試用例發揮更大的價值」進行詳細的介紹,敬請關注!

相關文章
相關標籤/搜索