《我所知道的軟件測試自動化》—關鍵字驅動的過去和未來
1.“關鍵字驅動”的由來
說到“關鍵字驅動”和“測試自動化”,就不能不提到 Mosley Daniel 的《軟件測試自動化》一書,這本書03年引入國內,04年市面上開始有賣,書中有兩個相信能吸引到很多 tester 的話題:
(1)腳本應該錄制還是編寫?——想知道答案的自己下載電子書看吧:)
(2)“數據驅動”和“關鍵字驅動”。
彼時的我,剛剛經歷了一次不成功的自動化實踐,雖然Rational Robot 提供了類似UI庫管理,數據池管理之類的強大功能,但是痛苦依然。對測試自動化理解的不夠深入,不知道該如何應對RAD模式下UI和業務快速調整,以及對C/S下非標準控件的識別等問題,導致了無法快速維護腳本、replay 次數不夠,回放通過率不夠,最后的結果是ROI無法滿足要求,自動化項目宣告結束。
帶著很多疑問的我原本想從那本書中找到些答案,遺憾的是那時功力實在太差,居然沒有看懂,唯一留下印象的就是作者在80年代就開始探索自動化回歸的技術,并且在90年代已經嘗試了“數據驅動”和“關鍵字驅動”的技術,想來當時 Robot framework 之類的都還沒有出現,所以我相信“關鍵字驅動”的技術源自這書的作者和他的朋友們。
2. 從“數據驅動”到“關鍵字驅動”
所謂的數據驅動,原本沒有什么特別的,無非就是把hard code 在腳本中的數據參數化出來,之所以算是Robot、WinRunner甚至QTP時代測試工具的賣點,其實主要是因為那個年代大多數system tester 不懂開發,總需要有個功能來幫助自己完成參數抽取、數據維護、自動替換之類的功能。
而關鍵字驅動,則進一步在技術上把 tester 分成了完全不懂技術的和懂點技術的,前者只能根據格式填寫一下 excel 表格,后者對工具/框架內置的所謂關鍵字庫進行增補或二次開發。
找些例子來看看吧。
(1)簡單的數據驅動。
如下面代碼,定義了一個class并實例化了幾個對象,用來存放不同的用戶登錄信息;而在負責完成登錄操作的 do_login_as() 方法中,把 send_keys 原來向表單中填充的數據參數化,根據每次調用 do_login_as() 方法時傳入的不同對象來實現用不同帳號登錄的效果——雖然我對以“登錄”為樣例介紹自動化測試腳本深惡痛絕,不過這里為了表述簡單,還是用了。(下面的代碼只是一個示例,不是直接用來運行的。)
其實數據驅動本來也沒有什么技術含量,寫過代碼的誰還不知道什么是變量啊?不過在早期的商業工具中,的確把這個作為了一個賣點,畢竟10年前的測試工具設計思路也與現在不同。早期的工具始終都假設”系統測試工程師不懂開發“,所以他們在開發測試腳本時需要借助類似錄制回放+編輯調試的模式;另外,對于數據驅動所需要的測試數據,最好也是通過工具內置的data pool 管理,通過表格編輯,甚至讀取 csv、excel 文件之類的。如果我們依照這個思路去實現自己的測試框架,那肯定是商業工具很有價值,畢竟自己實現data pool管理、外部數據文件讀取之類的功能,代碼量也不小,要處理好那些數據格式和內容校驗之類的,貌似跟我們所需要完成的自動化也沒啥太大關系。
可問題在于,為什么一定要有data pool+外部數據文件來實現”數據驅動“呢?
(2)傳統的“關鍵字驅動”
還是先用個例子來看看傳統的“關鍵字驅動”長什么樣子。
上面是一個 Selenium 0.x 時代Core模式下(什么是selenium的core模式和RC模式請自行google,不過話說現在已經全民webdriver時代了,不知道也就不知道吧)的例子(QTP的實現效果也類似),簡單說就是第一行是 test case name,下面3列開始進入正題,第一列表示你想干啥,第二列是被操作對象是誰,第三列是你對它干了啥。06年剛剛開始嘗試web測試自動化的時候,我們一度認為這是一個比之前的測試工具要智能的多的東東,不過在嘗試了很長一段時間之后,還是發現了這種模式下的問題,又逐漸轉回了編寫腳本的方式。
對比上面的第一個腳本,可以看出關鍵字驅動進一步屏蔽了底層的實現細節,例如,你只需要clickAndWait那個btnG,而不需要知道btnG到底是個啥,以及它在哪里,你只需要填寫表格。等你把一個個 test case 變成了一個個表格,把一個個step變成了一行行表格中的內容,基本上你的自動化測試就搞完了。——真的是這樣嗎?
現在回想一下,關鍵字驅動之所以會出現,可能初衷還是為了降低自動化實施的門檻——因為tester都不太懂開發嘛,所以開發能力強的人把框架實現出來,原來那些只會寫excel的 system tester填寫表格就可以了。也許現在還有很多公司會傾向于這個方案,美其名曰“分工協作,人盡其能”。不過關于這個問題,暫時先不展開討論,先看看這種傳統的關鍵字驅動模式會遇到什么問題。
首先,頁面對象的識別問題。這是任何一種基于UI實現回歸測試自動化的框架都會遇到的問題。在C/S時代,就已經出現了很多定制化UI組件難以被工具識別的問題,可好歹總逃不出windows的手心。到了web時代,前端實現技術百花齊放,而前端代碼的編寫也更是一個開發人員一個習慣,如果缺少統一的編碼規范,對于那些沒有使用id或者name之類屬性的頁面對象,傳統的關鍵字驅動框架就沒有例子中看起來那么美好了。當然,有人說xpath可以解決一切問題。嗯,xpath是很強,但是一個沒有開發經驗的tester想掌握它其實也不會比學會一點基本的編碼技術容易多少;另外,xpath并不是萬能的,在實際中還是有些它處理不了的情況。下面再給個例子(如果tester看不懂這個例子,估計學會xpath也有點困難):
上面這個圖中是一個表格,id列(第一列)和需求名稱列(第二列)下顯示的內容,都是可以點擊的超鏈接,最后的“操作”一列中的一個個小圖標也各自指向一個鏈接(分別是“變更”、“評審”、“編輯”、“建用例”),通過查看第一行記錄的html代碼,我們發現:
假如想要編輯一條記錄,沒有可利用的id或name屬性,唯一可用的是link;
link指向的url中包含了這條記錄的ID信息,因為這里是第一行記錄的代碼,所以都是341,而后面的每一行記錄的代碼都是各自的ID。
上面這個例子是企業應用中常見的場景,關鍵問題在于數據記錄ID是一個不可控因素,而數據記錄的title/name之類的是可控的,為了提高test case的可維護性和相互獨立,我們肯定不會依賴ID去模擬頁面操作,而是根據title/name之類取回ID信息,再拼裝回所需要操作的鏈接。這種情況下,xpath恐怕也搞不定了。(如果這里再涉及到要在幾個iframe之間跳來跳去,恐怕寫腳本的人就要崩潰了。)
當然,有人會說關鍵字驅動框架一般也可以定義function來實現類似的操作啊。唉,都到了編寫自定義function的地步了,干嘛還非要糾纏在關鍵字驅動上啊。
第二,腳本的可維護性問題。如一開始的例子,傳統的關鍵字驅動是一種純“面向過程”的腳本組織方式(就像C/pascal),表格中填寫的是一個操作序列。如果多個test case 都涉及到某個頁面,基本上就會在多個case中都看到類似 clickAndWait btnG這樣的內容,而一旦頁面中btnG改名叫buttonG了,或者 clickAndWait btnG與verifyTextPresent 之間增加了一個 clickAndWait XXX的step,那基本上每個case都需要修改。
嗯,問題來了,當你的腳本數量從1增長到100、1000的時候,當UI的變動無法避免的時候,當你發現100個case回歸執行只有90個通過,執行失敗的10個需要逐個檢查錯誤日志和查看截圖,再挨個修改的時候,當下次回歸測試又發生這種問題的時候——基本上這就是一個死循環了。如果解決不了根本問題,前期投資可以舍棄了,別糾結了。
當然,有人說關鍵字驅動已經進化了,可以跟最新的webdriver結合起來,提升關鍵字的封裝層次,解決這個可維護性的問題。好吧,這個問題等下再詳細說。
第三,腳本的可擴展性問題。在大規模實施自動化的過程中,腳本一般都會簡單的是一行行的browser.find_elmenet_by_id(xxxx).click() 這樣的模式,根據各種條件來判斷執行的分支,進行各種異常處理,第三方類庫/包的調用,主機環境的訪問,諸如此類,這些對于所有的3GL/4GL來說其實都很容易實現,但對于傳統的關鍵字驅動來說,嗯,也可以實現,大概是下面這個樣子【摘自robot framework(此robot非rational robot)】:
下面是一個在 keyword 表格里面實現的 FOR 循環:
有人可能會說“你看,關鍵字驅動框架也可以擴展的很強大啊!”。是,在programming 的世界中,沒有什么不能做的,不過都弄到這個份兒上了,學習這一套東西跟學習一個標準的編程語言還有什么差別嗎?先不說這樣的框架越擴展越難維護,可靠性也就越差,單單這些關鍵字的用途被局限在自己的框架中,你所積累的知識和經驗無法重用到其他測試代碼的編寫中這一個理由,就應該徹底放棄這種方式了。
如果要說的直白一些,傳統的關鍵字驅動框架的時代在前幾年就已經開始遠去(是had been,不是have been),我們感謝上一代tester的努力探索和實踐,但最終歷史證明這是一個不算成功的嘗試,一個框架如果不具備開放性,一切都自給自足,那么有一天這也會成為限制自己發展的最大原因。
(3)穿馬甲的“關鍵字驅動”
時代在進步,關鍵字驅動也在進步,這個領域中的代表 robot framework(此robot非rational robot) 也在進步,于是,test case 變成了下面這個樣子。
依舊不變的是“表格”,改變的是填寫方式——其實這背后的,是關鍵字定義終于被開放出來,tester可以自己定義keyword然后“注冊”到框架中,而那些依然沒有學會基本編程技能的tester,繼續用這些keyword重復上個時代的事情——填寫表格。
其實相對于最初對關鍵字驅動的定義,這個真的已經不是關鍵字驅動了,如果非說它是,那么只能說上個時代的關鍵字驅動中,test case 表格的每行都是一個頁面操作,而“新的”關鍵字驅動中,test case 的每行都已經是一個完整的業務操作,以上面的“Create Valid User” step 為例,robot framework希望的實現方式是tester通過python等4GL實現一個同名的function,這個function接受兩個參數,分別是“fred”和“P4ssw0rd”,再把這個function注冊到robot framework中。而“Create Valid User”內部的實現,可以類似于一開始“數據驅動”中的那個例子,充分利用4GL的特性和已有的其他第三方組件(例如webdriver),來實現各種復雜的基于UI的操作,這樣也就解決了剛剛“傳統的關鍵字驅動”所遇到的問題。
最后,當完成了這個function的開發并在robot framework中注冊后,做手工測試的system tester就可以很容易的把原本excel中的一個個case轉變為自動化腳本了。
其實這個思路有它的優點,例如:通過分工協作降低實施門檻,可以一開始就編寫符合robot所需格式的manual test case,等到keyword開完全了以后這些case就可以直接導入執行了;不再自給自足,而是保持一定的開放,并利用其他第三方組件的特性。這樣很大程度上解決了自動化項目實施遇到的人員能力問題和可維護性、可擴展性的問題。
另外,新的關鍵字驅動還有一個更加先進的“近親”BDD作為參照,很容易把它的一些實踐也一起融合進來。
一切看起來都很美好,不過問題也還是有。
表格化的test case畢竟不同于編寫代碼,調試就變成了一個問題,如果寫錯了關鍵字的一個字母,要及時發現并定位到問題就不那么容易。當然,可以再開發一個web平臺,讓編寫case的人僅能從一個list中選擇已經定義好的keyword,不過這個成本恐怕就不是一般研發團隊能承受的了。
作為一個軟件,易用性和復雜度總是成反比的,當框架提供了方便的表格化編寫case功能時,也相對的增加了底層的復雜度(雖然沒看過robot framework的代碼,但是相信底層代碼的分層也應該比較復雜),對于想要真的掌握框架的團隊來說,無形中增加了一道門檻。另外,復雜度與可擴展性也是成反比的,就像我可以用木頭做一輛車,也可以把木頭車拆了做些別的東西,但是我沒法把一輛汽車拆了弄成別的東西——前兩年廣東美院那位把解放卡車拆了做成關公像的牛人除外。當然,最終實施自動化時到底如何進行框架選型,就要團隊自己在易用性/復雜度/可擴展性上進行評估了。
把excel里面的manual test case通過新的關鍵字驅動直接變成可執行的腳本是最好的方法嗎?這似乎只是一個傳統system test 的慣性思維在作怪,為什么沒看過開發人員把unit test 也寫到一個個表格里面?為什么manual test case 就一定要先寫在excel里面,而不是一開始就是代碼?
如果僅僅是考慮把 step組裝起來,再把case組織成suite執行,其實代碼實現上可以說毫無技術含量,但是對于一個沒有開發經驗的tester來說,這畢竟是一個跟coding簡單親密接觸的機會,可以讓tester從低難度的代碼開始培養興趣和信息。而keyword,無論新的還是舊的,卻剝奪了這個機會;當tester希望學習框架的時候,會發現表格的層面跟下層框架之間的不是樓梯,而是一道溝。
3. “關鍵字驅動”的未來
我們如今所處的環境總是在變化著,今天與10年前相比,最大的變化就是測試行業獲得了極大的發展,大多數企業都認可了測試工作的重要性,并且開始思考如何提升測試工作自身的質量和效率,而且不同規模的企業都在探索著合適自己的研發流程和技術;而tester們的技術能力也在不斷增強,至少能寫代碼的人比5年前多了很多。當然,還要感謝開源世界帶來的眾多框架、組件,讓自動化的門檻不斷降低。
就像傳統的關鍵字驅動已經遠去一樣,新的關鍵字驅動未來會如何,大家討論吧。:-)
posted on 2014-07-31 09:36 順其自然EVO 閱讀(355) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄 、selenium and watir webdrivers 自動化測試學習