做者: 殷坤 來源: InfoQ html
測試是爲了保證軟件的質量,敏捷測試關鍵是保證能夠持續、及時的對軟件質量狀況進行全面的反饋。因爲在敏捷開發過程當中每一個迭代都會增長功能、修復缺陷或重構代碼,因此在完成當前迭代新增特性測試工做的同時,還要經過迴歸測試來保證歷史功能不受影響。爲此咱們指望: web
測試範圍足夠廣: 編程
測試頻率足夠高: 瀏覽器
但實際狀況每每不遂人願: 併發
實際測試周期變短: 框架
有效測試資源稀缺: 編程語言
所以因爲客觀上的資源和時間限制,完整的、及時迴歸測試在人工測試狀況下,每每是不可能完成的任務。團隊內部也會產生各類爭執: 函數
爭執越演越烈,最終有團隊成員爆發了:「這簡直不是人乾的活!」。 工具
您怎麼看待這句話呢? 佈局
其實話糙理不糙,用更理性的語言翻譯一下就是「有些工做不該該以人工的方式來完成」,好比:
經過自動化測試能夠極大的提高迴歸測試、穩定性測試以及兼容性測試的工做效率,在保障產品質量和持續構建等方面起到舉足輕重的做用。特別是在敏捷開發模式下,自動化測試是必不可少的。
目前業界的商業/開源自動化測試工具備不少,好比,功能測試工具備QTP、Selenium等,性能測試有LoadRunner、JMeter等。其工做原理無非都是經過「測試腳本」和「測試數據」來完成「測試過程」,並比較「測試結果」,進而造成「測試報告」。
本文不對這些測試工具的差別或優劣進行對比,只以做者目前採用的Selenium爲例進行分析:敏捷開發模式須要自動化測試,但自動化測試自己的敏捷性又如何呢?
Selenium是針對Web應用的開源自動化測試工具,經過編寫模擬用戶操做的腳本,它會打開瀏覽器對Web應用進行黑盒測試。能夠方便的用於功能測試、兼容性測試、 穩定性測試及併發測試。目前已被主流瀏覽器廠商普遍支持,同時也是不少其它自動化測試工具(好比,RobotFramework)的底層核心技術。Selenium由IDE、Remote Control(簡稱RC)、WebDriver、Grid四個工程組成:
是一個用於錄製/回放測試腳本的Firefox附加組件,錄製的腳本能夠生成基於Selenium RC的測試代碼(Java、Ruby、C#等)。適用於快速入門,不太適用於實際較大的測試項目;
RC由Server和Client組成兩部分組成,Server負責加載/關閉瀏覽器以及做爲HTTP代理來訪問Web應用,Clinet支持多種編程語言和測試框架(TestNG、JUnit、NUnit等)。
WebDriver做爲Selenium2的核心特性提供比RC更簡潔易用的API,是官方推薦的RC替代方案。能夠更好的支持動態網頁,不須要再額外啓動一個獨立的Server。
是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();.
腳本解讀:
二、在新增用戶頁面,輸入「賬號」、「密碼」、「姓名」,選擇「性別」、「生日」和「國籍」,而後點擊「保存」按鈕,回到用戶列表頁面,並判斷是否增長成功:
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);
腳本解讀:
三、刪除剛剛增長的人員,而後判斷是否刪除成功:
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);
腳本解讀:
經過上面的腳本就能夠實現「用戶增長、刪除」的自動化測試,而且能夠跨瀏覽器。看到這裏您會不會以爲總體還不錯,若是測試腳本再能經過錄制的方式自動生成就更好了!
「看」起來確實還不錯,但在實際項目中用起來就沒那麼爽了。這實際上是在技術/工具選型時廣泛存在的現象:在驗證/試用階段的評價很高,但在投入生產使用時會遇到各類各樣的問題,所以你們在選型階段除了考慮功能,還要考慮技術/工具自己的開放性和可擴展性。
上面的方案單純從技術的角度來說是很不錯的:開源、社區活躍、標準化程度高、支持跨瀏覽器、腳本回放穩定、可集成性高,等等。
可是若是就這樣應用在實際項目中,會從過程的角度暴露一些棘手的問題:
測試人員和開發人員好像都有編寫這些測試腳本義務,但彷佛又都有不寫的理由。
在敏捷開發過程當中須要快速響應需求的變化(新增、變動),這一點整個團隊都好理解。所以若是需求發生變化,開發人員修改代碼、測試人員修改測試 腳本,一切瓜熟蒂落,你們相安無事。可是在用戶需求沒有變化時,開發人員頻繁修改代碼的狀況也很常見:好比,修改Bug、針對「壞味道」作重構、調整頁面 佈局或樣式。因而在「毫無徵兆」的狀況下,測試腳本又沒法執行了!
這時候測試人員可能會質問開發人員:「作以前怎麼不想清楚?都已經測試完成的功能,爲何還老是反覆修改?何時代碼才能穩定?」。
而開發人員此時也會很是義正詞嚴:「有Bug能不改麼?頁面佈局不合理致使用戶體驗差,能不改麼?並且敏捷中的一個重要的實踐就是重構啊」。
你們又是彷佛都有道理、也都有苦衷。我雖然做爲測試人員,可是在這個問題上仍是「偏向於」開發人員的: 在軟件生命週期的各個階段(需求、設計、開發、測試)中,後面的階段對前置階段是有必定依賴的,因此越日後期響應變化的難度越大。好比,在「開發」環節不 僅須要響應「需求」的變化(新增、變動),並且須要響應「設計」的變化。從這個角度來看,「測試」本就應該響應「開發」的變化。
對於在實際項目自動化測試過程當中遇到的上述問題,歸根究竟是由於「自動化測試方案自己的敏捷程度不夠」,主要體如今以下三個方面:
一、 學習成本高
測試人員除了要掌握WebDriver接口以外,還要掌握XPath、TestNG的用法,甚至還須要對功能的前臺實現有必定了解。
二、 腳本維護困難
敏銳的開發/測試人員從上面的示例腳本中,能夠立刻嗅出一些「壞味道(Bad Smell)」: 代碼類似度很是高、可能變化的數據被硬編碼在測試代碼裏、代碼可讀性差、測試代碼與頁面源碼耦合度大,等等。這些壞味道的出現,一般意味着須要進行重構, 不然會愈演愈烈,最終變得尾大不掉。
【注】業界常見的測試工具本質上仍是針對頁面源碼來編寫(或生成)測試腳本的,即便提供了錄製工具,此類腳本的可讀性和後期可維護性仍是很是差的。
三、 斷言條件繁瑣
業界常見的測試工具即便提供錄製腳本的功能,可是對於「斷言」仍是須要人工插入的(工具作不到智能的判斷咱們想要在哪裏設置斷言),因而斷言就成了自動化測試人員的「噩夢」。
斷言對象可能很「多」,頁面的信息量每每很大,須要在測試腳本中爲每一個斷言對象(好比,頁面某個文本框的值)補充斷言語句。
預期結果是可能「變」化的,甚至是動態的,所以預期結果的值若是與腳本邏輯耦合在一塊兒,未來極難維護。 斷言機制比較「呆」板,對於 未設爲斷言對象的字段,若是發生錯誤也是沒法感知的,而且難以對於UI樣式或UI邏輯(好比,翻頁圖標應該灰顯)進行斷言。
換個角度能夠理解爲,若是這樣的斷言條件「多」的話,整個測試用例集會「變」的很是「呆」板!
想要有效的改善這些問題,就必須讓自動化測試變得「敏捷」起來!
在本系列後續的文章中會就「如何讓測試腳本易寫、易讀、易維護」、「如何讓斷言再也不成爲測試的負擔」、「如何經過持續集成讓測試用例發揮更大的價值」進行詳細的介紹,敬請關注!