敏捷自動化測試(1)—— 我們的測試為什么不夠敏捷?

測試是為了保證軟件的質量,敏捷測試關鍵是保證可以持續、及時的對軟件質量情況進行全面的反饋。由于在敏捷開發過程中每個迭代都會增加功能、修復缺陷或重構代碼,所以在完成當前迭代新增特性測試工作的同時,還要通過回歸測試來保證歷史功能不受影響。為此我們期望:

  • 測試用例要覆蓋所有功能;
  • 要在各種可能的環境下作兼容性測試;
  • 系統的穩定性、性能都要測試;

測試頻率足夠高:

  • 每日構建產生的版本要保證可用;
  • 每個迭代都需要對歷史功能做回歸測試;
  • 釋放前或上線后如果打了補丁,就需要回歸;

但實際情況往往不遂人愿:

實際測試周期變短:

  • 上線時間提前確定,研發進度延期,測試計劃被迫延后;
  • 最后階段經常會臨時增加測試任務;
  • 所有人都知道還需要再經過一輪測試,但時間沒有了;

有效測試資源稀缺:

  • 臨時從其他項目抽調的測試人員不能立刻有效的開展測試工作;
  • “搞不清楚”本項目的研發人員到底是不會做測試還是不愿做測試;

因此由于客觀上的資源和時間限制,完整的、及時回歸測試在人工測試情況下,往往是不可能完成的任務。團隊內部也會產生各種爭執:

  • 提交給測試的版本為什么研發人員不先做通過性測試?
  • 這次代碼改動量不大,有必要再花那么多時間回歸么?
  • 當初不是承諾這次修改肯定不會影響以前的功能么?
  • 怎么不早說要支持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實現的“增加”和“刪除”測試腳本(只示意部分關鍵代碼)。

1、在用戶列表頁面點擊“新增”按鈕,跳轉到新增用戶頁面:

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

腳本解讀:

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

2、在新增用戶頁面,輸入“帳號”、“密碼”、“姓名”,選擇“性別”、“生日”和“國籍”,然后點擊“保存”按鈕,回到用戶列表頁面,并判斷是否增加成功:

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是存在的(不為空);

3、刪除剛剛增加的人員,然后判斷是否刪除成功:

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能不改么?頁面布局不合理導致用戶體驗差,能不改么?而且敏捷中的一個重要的實踐就是重構啊”。

大家又是似乎都有道理、也都有苦衷。我雖然作為測試人員,但是在這個問題上還是“偏向于”開發人員的: 在軟件生命周期的各個階段(需求、設計、開發、測試)中,后面的階段對前置階段是有一定依賴的,所以越往后期響應變化的難度越大。比如,在“開發”環節不僅需要響應“需求”的變化(新增、變更),而且需要響應“設計”的變化。從這個角度來看,“測試”本就應該響應“開發”的變化。

對于在實際項目自動化測試過程中遇到的上述問題,歸根到底是因為“自動化測試方案本身的敏捷程度不夠”,主要體現在如下三個方面:

1、 學習成本高

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

2、 腳本維護困難

敏銳的開發/測試人員從上面的示例腳本中,可以馬上嗅出一些“壞味道(Bad Smell)”: 代碼相似度非常高、可能變化的數據被硬編碼在測試代碼里、代碼可讀性差、測試代碼與頁面源碼耦合度大,等等。這些壞味道的出現,通常意味著需要進行重構,否則會愈演愈烈,最終變得尾大不掉。

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

3、 斷言條件繁瑣

業界常見的測試工具即使提供錄制腳本的功能,但是對于“斷言”還是需要人工插入的(工具做不到智能的判斷我們想要在哪里設置斷言),于是斷言就成了自動化測試人員的“噩夢”。

斷言對象可能很“多”,頁面的信息量往往很大,需要在測試腳本中為每個斷言對象(比如,頁面某個文本框的值)補充斷言語句。

預期結果是可能“變”化的,甚至是動態的,因此預期結果的值如果與腳本邏輯耦合在一起,將來極難維護。 斷言機制比較“呆”板,對于 未設為斷言對象的字段,如果發生錯誤也是無法感知的,并且難以對于UI樣式或UI邏輯(比如,翻頁圖標應該灰顯)進行斷言。

換個角度可以理解為,如果這樣的斷言條件“多”的話,整個測試用例集會“變”的非常“呆”板!

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

轉載于:https://www.cnblogs.com/xinleishare/p/4256670.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376300.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376300.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376300.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習c++

目錄 一 、 boost庫: 1. 多線程 c boost多線程學習(一) 二 、數據庫: 三、socket編程: c socket學習(1.1) c socket學習(1.2) c socket學習(1.3&#x…

mysql5.6與mysql5.5不同

1.編譯階段 要明白with與without的區別,選項值分1和0,或者對應為on或off,代表支持與不支持;with的1(on)與without的0(off)是同樣的,with的0(off)與…

c++ 基本排序算法學習

C實現排序算法 代碼地址 vector<unsigned int> cVec; int nSize cVec.size();1 冒泡排序 算法思路&#xff1a; 每兩兩相鄰的數值都會比較大小&#xff0c;前面比后面大的時候就交換位置&#xff0c;否則就不動。 代碼&#xff1a; void BubbleSort() {//優化&#x…

ios 程序學習

馬上著手開發iOS應用程序&#xff1a;五、提交應用與尋找信息 2013-01-11 15:36 佚名 apple.com 我要評論(0) 字號&#xff1a;T | T本文介紹了您已經學習完如何開發一個優秀的iOS應用之后&#xff0c;應該掌握的內容&#xff0c;包括將您的應用提交到App Store讓其他人下載&am…

解決SimpleButton被移除后保持OVER狀態

假設場景中有一SimpleButton叫testBtn,執行下面操作&#xff1a;1.鼠標移上testBtn&#xff0c; testBtn狀態變為OVER2.移除testBtn&#xff0c;removeChild(testBtn)3.5秒后重新添加testBtn到場景此時&#xff0c;看見testBtn還是OVER狀態。解決方法&#xff1a;1.記錄testBtn…

c++ socket學習(1.1)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 windows 如何創建客戶端與服務端通信&#xff1f; TCP&#xff1a; 服務端 在windows先告訴程序我們要使用哪個版本的winsock&#xff0c;成功調用了它才能繼續下去 #…

c++ socket學習(1.2)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 windows 如何創建客戶端與服務端通信&#xff1f; UDP&#xff1a; 這次就沒什么客戶端服務端好說了&#xff0c;UDP是沒有無連接的 所以改叫接收端和發送端吧 接收端 …

js高級功能與高級需求、高級期待

http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html 簡單練習題&#xff1a;http://tieba.baidu.com/p/2189347922 ---------------------- scope鏈 閉包 Javascript屬性prototype node.js metaprogramming AMD、CMD機制 http://www.makumo.com/js-modules-amd-c…

synchronized同步鎖

在多線程的情況下&#xff0c;由于同一進程的多個線程共享同一片存儲空間&#xff0c;在帶來方便的同時&#xff0c;也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突&#xff0c;有效避免了同一個數據對象被多個線程同時訪問。由于我們可以通過 private…

c++ socket學習(1.3)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 在這里c socket學習&#xff08;1.1&#xff09;學到了怎么樣建立TCP&#xff0c;然后通過TCP連接發送、接收信息。 但是都是一次性的&#xff0c;當時是接收信息后就結束…

一個一線城市的IT白領的生活成本:3萬/年

自從大學畢業&#xff0c;經濟獨立&#xff0c;就開始全面統計各種生活開支。仔細的去統計下&#xff0c;發現開銷還是挺大的。 定理&#xff1a;開銷越大&#xff0c;就意味著你每個月的收入必須越高。 三族鼎立節余族: 收入-開支 > 0月光族&#xff1a;收入-開支 0透支族…

android 編譯共享ccache的緩存

1. android自帶的ccache版本號(2.4版本號)過低&#xff0c;是無法支持以上的功能的&#xff0c;須要使用新版ccache。2. 最新的ccache請到http://ccache.samba.org/download.html下載3. 下載解壓之后&#xff0c;在linux底下進入ccache文件夾&#xff0c;執行:./configure./mak…

一位軟件工程師的6年總結

作者&#xff1a;成曉旭 “又是一年畢業時”&#xff0c;看到一批批學子離開人生的象牙塔&#xff0c;走上各自的工作崗位&#xff1b;想想自己也曾經意氣風發、躊躇滿志&#xff0c;不覺感嘆萬千……本文是自己工作6年的經 歷沉淀或者經驗提煉&#xff0c;希望對所有的軟件工…

c++ socket學習(1.4)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 前面學到了TCP怎么循環發包&#xff0c;但是TCP連接的話會出現一個問題粘包。 TCP連接接收到的數據并不是馬上讀取到內存里面的&#xff0c;而是放在緩沖區&#xff0c;讓…

mongodb中分頁顯示數據集的學習

mongodb中分頁顯示數據集的學習 這次繼續看mongodb中的分頁。首先依然是插入數據&#xff1a; 1&#xff09; db.Blog.insert( { name : "Denis", age : 20, city : "Princeton" } ) db.Blog.insert( { name : "Abe", age : 30, city : &quo…

學習編程,英語很重要!!

學會編程&#xff0c;可能不需要英語多好&#xff0c;但是學號編程&#xff0c;英語真的很重要&#xff01;&#xff01;&#xff01; 好多文檔&#xff0c;demo全是英文的&#xff0c;蛋疼&#xff0c;應許需要學習&#xff01;&#xff01;&#xff01;轉載于:https://www.cn…

c++ socket學習(1.5)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 這次來試一下使用TCP來傳輸文件&#xff0c;其實傳輸數據和差不多&#xff0c;就是多一個讀取文件&#xff0c;和一個寫文件而已。 服務端 int readlan 100; std::ifst…

matlab生成HEX文件-任意信號 大于64K長度

HEX文件格式不贅述&#xff0c;寫里直接放上代碼。請批評改正。 1 %%convert a signal data into hex file format2 % data format:16bit 3 % signal length: less than 2^24-14 % author: Yang Li yangli0534gmail.com5 % data:2015.01.276 7 clear all;8 close all;9 clc; 10…

移動端網頁中ViewPort的使用

<meta name"viewport" content"widthdevice-width,target-densitydpihigh-dpi, initial-scale1.0, minimum-scale1.0, maximum-scale1.0, user-scalableno"> <meta name”viewport” content”widthdevice-width, initial-scale1.0, user-scalabl…

c++ socket學習(1.6)

本文學習相關資料&#xff1a; C/C socket編程教程 環境&#xff1a;vs2015 源碼&#xff1a;本文代碼 這次來看看UDP 之前在c socket學習&#xff08;1.2&#xff09;講過UDP怎么發送了&#xff0c;那現在來做一個可以一直發送的。 這次沒有什么接收端和發送端了&#xff0…