本節書摘來自異步社群《精通qtp——自動化測試技術領航》一書中的第1章1.7節描述性程式設計(descriptive programming),作者餘傑 , 趙旭斌,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
1.7 描述性程式設計(descriptive programming)
精通qtp——自動化測試技術領航
階段要點
描述性程式設計不高深。
描述性程式設計的兩種寫法。
描述性程式設計執行個體介紹。
1.7.1 一點都不高深的描述性程式設計技術
qtp剛進入國内不久時,各大測試論壇曾經有過一場持續了多年的争論,引起這場争論的導火線就是對象庫程式設計(以下簡稱orp)和描述性程式設計(dp)。這場争論持續了至少3年以上。争論的話題都是使用qtp進行自動化測試,其測試腳本是使用對象庫程式設計好還是描述性程式設計好,有興趣的讀者完全可以在51testing論壇中輸入一些關鍵字進行搜尋,如“對象庫描述性程式設計”等,相信應該還能重新找到不少資訊。
大約從2009年開始,随着大家對qtp技術的了解,orp與dp的争論已經越來越少了,因為随着時間的推移,國内的qtp自動化測試技術也發展到了一定高度,使得越來越多的測試人員更傾向于orp!為什麼?orp技術為什麼好過dp技術?有什麼依據?暫時先不說,先說說大多數當初支援dp的人們的一些心态:
第一種也是最典型的一種,就是描述性程式設計這個名詞裡嵌套了“程式設計”兩字,這得怪mercury開發qtp的時候提出了dp這一概念!這“程式設計”兩個字可誤導了不少測試新人。相信大家都知道,國内測試行業的很多新人大多都是其他行業轉型過來的,相對做測試的門檻沒有做開發那麼高,很多也沒有經受過系統的計算機軟體方面的學習,是以對“程式設計”一直很向往,覺得程式設計很難,是以一聽到qtp的描述性程式設計這個概念,就覺得是個很高深的技術。在早期,就是因為這種心态使得一大批測試新人在慢慢熟悉并會使用qtp以後,明明可以不去使用dp也硬要去使用,以顯示自己是技術牛人,其實這種舉動是化簡為繁并脫離了自動化測試的本意。當然,很多支援dp的人不是屬于炫耀範疇的,是屬于被“程式設計”兩字忽悠了的範疇的。
第二種也是比較典型的,因為以前大家都認為dp很高深,覺得dp是qtp中的精髓。是以,如果使用dp寫腳本并送出給測試經理看,那上司一定會認為你很牛。很明顯,以上兩種都是稍許帶有貶義的。
第三種争論的焦點是自動化測試架構,配合自動化測試架構,在進行qtp程式設計的時候到底用orp好還是dp好?這個也可以說是3個中唯一一個真正對國内自動化測試領域的提高有價值的争論,因為的确是各有好處的!關鍵不是使用哪種qtp程式設計技術,更多的焦點是架構設計的怎麼樣。
是以,排除第三種自動化測試架構的特殊情況,選擇orp技術的人們是理智的人群,咱也不能說選擇dp的人們就是不理智的,但是可以肯定,如果明明可以使用orp技術卻還硬要使用dp技術的人們是肯定不理智的。
很自然的,對象庫程式設計就是我們上一章節剛剛重點介紹過的非常強大的一個功能,而描述性程式設計就是本章節要介紹給各位新人讀者的一項程式設計技術。其實呢,本人一開始聽到qtp的描述性程式設計技術的時候也一直以為是一門很高深的技術。事實上……下面就會用執行個體證明給大家看,其實dp就是這麼簡單的一回事!現在基本上大家都認可了orp是qtp自動化測試的首選,為什麼?因為orp的确經得住考驗,而且在下面的“終極對決”的小節裡,還會讓orp和dp來一次大“pk”來證明,為什麼選擇orp是理智的,為什麼大家最終還是傾向于orp,并且還會介紹一下orp相比dp的一些優越性。
1.7.2 掌握描述性程式設計的兩種寫法
首先,需要用最簡單和生動的例子來介紹描述性程式設計的概念,或者說它到底具體是什麼,我們仍然用百度頁面,請先看下面圖1-181以及代碼段。
相信讀者應該都已經很熟悉圖1-181了,它是一個對象庫,裡面添加了一些需要操作的百度網站的對象。接下來我們來看代碼的實作:
browser("百度一下,你就知道").page("百度一下,你就知道")._
webedit("wd").set "qtp自動化測試技術領航"
webbutton("百度一下").click
以上這段代碼讀者應該也已經很熟悉了。它就是用對象庫程式設計産生的代碼。但是,讀者有沒有思考過一個問題,假設這些對象沒有添加到對象庫裡怎麼辦?qtp還能工作嗎?完全可以!qtp提供了描述性程式設計(descriptive programming)這個解決方案。事實上,在很多情況下,對象都不會順我們的意思,經常會面臨“不是我們想不想把對象添加到對象庫,而是根本沒法添加”這種尴尬局面。是以,此時“dp”可以擔起重任了,替“orp”完成它無法完成的事!這裡暫時先不介紹無法添加對象的案例,我們先存心使對象無法生存于對象庫中。把之前添加好的百度的對象全部删除,如圖1-182所示。
就像我們現在看到的一樣,已經沒有對象供我們使用了,怎麼辦?目前需要做的唯一的一件事是“照搬”!搬什麼?雖然對象庫裡的對象沒了,但是我們完全可以将對象庫中的内容直接搬遷到腳本中去。又是什麼内容是需要搬遷到expert view中去的呢?—就是我們所要用的對象的一個個屬性及其屬性值,一起來看下是怎麼搬遷的,推序如下所示:

'代碼1
browser("micclass:=browser").page("micclass:=page")._
webedit("name:=wd").set "qtp自動化測試技術領航"
'代碼2
webbutton("name:=百度一下").click
描述性程式設計大解析(第一種)。
整個搬遷過程完成了,這就是描述性程式設計,最簡單地說,dp無非就是在描述每個對象的屬性和屬性值,通過這個原理來虛拟成對象庫中的對象,隻是對象庫是隐形的。
那先來看看第一句代碼(代碼1):描述性程式設計的運作原理完全是和對象庫程式設計一緻的,是以在這裡先去描述一個最“上層”的對象“browser”,對象名稱寫好以後用上一對括号,然後在括号裡依次從左到右填入引号、一個屬性名稱、一個冒号、一個等号、一個屬性值、引号。這個就是第一個形式,即:對象名("屬性名:=屬性值")。讀者必須要記住這個形式(描述性程式設計的形式一共有兩種,在後文中會繼續介紹第二種),有了前面的描述模闆,接下來就完全可以依葫蘆畫瓢了。按照對象的結構順序一層一層地往下描述,直到定位到最終想要操作的對象,最後給它一個方法,整個過程就結束了。看腳本中的代碼1就是這樣的。是以,同樣的道理在代碼2中就不講了。
再總結一下,其實描述性程式設計就是将原對象庫程式設計中括号内的“對象名”(見圖1-183)換成一種描述語言,它描述的仍然是這個對象,隻不過不再是封裝好的現成的對象,而是需要現場描述(封裝)。
第一種描述形式已經介紹完了,但是關于第一種描述性程式設計方式的内容還沒有講完,在前面那段代碼中,都是以單屬性及其屬性值來描述一個對象。其實在qtp中,還可以同時描述多個對象,但是數量還是會有一個極限的,可以描述的屬性必須是qtp内置的(怎麼才能知道哪些屬性是qtp内置的,可供我們描述的,以及一些屬性值的設定等,都會在下一小節的内容中介紹到),先讓我們一起來看下面這段腳本:
webedit("html tag:= input","name:=wd").set "qtp自動化測試技術領航"
webbutton("html tag:= input","name:=百度一下","type:= submit").click
上面這段代碼中,同樣也是兩句代碼,第一句的最終定位對象用了兩個屬性去描述,第二句的最終定位對象則用了3個屬性去描述。在這裡同樣要告訴讀者們必須記下來的一個規則,那就是描述多個屬性時,屬性間用逗号隔開,這個逗号必須是英文狀态下的。另外,描述性程式設計的文法是對了,但是如果描述的屬性值沒有設定對,那qtp是不會執行的,例如,假設将上面這段代碼中的第二句代碼中的最終對象“webbutton”所描述的屬性type改成“error”這個值,其結果讀者可以自行去嘗試下,看看qtp會不會執行。
還要讓讀者記住第二條規則,那就是如果父對象描述了,子對象則一定要描述,不然qtp會報錯,來看下面這個示例腳本:
'正确 – 父對象如果描述了,子對象必須描述
'錯誤 – 父對象描述了,子對象沒有描述
browser("micclass:=browser").page("百度一下,你就知道")._
圖1-184是父對象描述後子對象沒有描述導緻qtp報錯的截圖。
但是子對象如果描述了,父對象可以不描述,當然,父對象不描述又不報錯的前提是要被添加到對象庫中,一起來看下面這個示例腳本:
browser("百度一下,你就知道").page("百度一下,你就知道").webedit("name:=wd").set "qtp自動化測試技術領航"
至此,第一種描述性程式設計方式的基本内容全部介紹完畢。
描述性程式設計大解析(第二種)。
現在要介紹第二種描述性程式設計方式,那就是使用description對象。使用該對象可以傳回包含一組property對象的properties集合對象。property對象由屬性名和值組成。然後,可以在語句中指定用傳回的properties集合代替對象名(每個property對象都包含一個屬性名和值)。
要建立properties集合,需要先建立properties對象,使用以下文法進行:
set objdescription = description.create()。
建立完畢後,就可以在運作會話期間在properties對象中添加、編輯、删除或檢索屬性和屬性值了。也可以這麼了解,就是将對象的屬性及其屬性值的描述封裝在一個特殊的description對象中。例如,假設現在需要完成以下這個操作,見下面這個腳本:
完全可以通過description對象來實作同樣的功能,參見下面這段代碼:
set "注意此時描述對象的括号内是不需要加引号的,加了引号反而就錯了!"
'最後需要記住釋放對象,可以從最裡面一層開始釋放直到最外面一層
兩種描述性程式設計方式都已經介紹完了,本人認為第一種更适合應用于普通腳本中,或者這麼說,在對象庫程式設計無法完全任務的時候,描述性程式設計臨時加上一句,這樣做顯得更加直覺,代碼數量也更加少。但是很明顯的缺陷就是無法做到複用。第二種描述性程式設計的方式,個人認為更适合應用于基于架構的腳本中,從表象上看雖然比前者會多寫幾句代碼,但是這種方式的複用性遠遠優于前者,是以,具體選取哪一種方式都應按項目的實際情況界定。
1.7.3 object identification與spy結合dp的妙用
在前面的章節中,已經認識了object identification和spy,在本小節中,這兩位老朋友又要粉墨登場了。它們不止可以與對象庫程式設計結合,同樣可以和描述性程式設計結合。接下來,就分别聊聊它們與描述性程式設計的默契搭配。
在前面的小節中已經将描述性程式設計的文法教給大家了,文法是固定的就兩種,但是描述的屬性就非常多了,相信很多讀者都已經開始疑問或者迷茫了,怎麼知道哪些屬性可以描述,全背出來了?其實不可能啦!本書在一開始的章節中就提到學習qtp是任何知識點都不用背的。是以,在這裡本人公布:首先介紹的是object identification。通過oi就可以知悉一切對象可描述屬性,如圖1-185所示。
如圖1-185所示,這就是oi的界面,應該很熟悉了吧,之前都已經認識了,是以在這裡一些基本介紹就不重複了。現在選中的就是剛才描述過的一個控件“webbutton”,預設出現在mandatory properties視窗裡的就是系統預設的一些該控件的重要屬性,如果要描述一個控件,首先先描述這些最重要的屬性(也許這種說法不科學,但是本人覺得這說法很實際和現實)。如果預設的屬性滿足不了你的需要,那你隻需點選add/remove就可以了,裡面可以讓你新增或删除一些其他的屬性,如圖1-186所示。
當然,不但可以删除一些備選的屬性,也可删除系統預設屬性。另外,在此主要要講一下browser和page對象的描述,先來看看oi吧,如圖1-187和圖1-188所示。
我們可以看到,browser和page是沒有系統預設屬性的。因為這兩個控件比較特殊,一般情況下,都會使用class name或者creationtime這兩個屬性來描述該對象,它們在oi裡可是沒有的。class name可以從spy裡看到,說到class name我們也不得不回顧一下之前講過的一個挺重要的知識點,就是class name必須要寫成micclass。讀者再傳回看看在上一個小節中,描述browser和page的時候是不是使用了micclass?
接下來講解的是spy,spy在描述性程式設計中也是經常被調用的,因為oi用于定位所要描述對象的屬性,而spy就是定位描述屬性的屬性值,它們絕對是默契的搭檔!描述性程式設計也就是因為有了它們,才可以應用起來,如來看看下面這張spy圖,如圖1-189所示。
本小節的内容相對比較簡單,不過簡單不代表實用性就不高,恰好是相反的!最後,告訴讀者描述性程式設計可描述的屬性都是封裝接口屬性,不是自身接口的屬性,務必切記!
1.7.4 描述性程式設計的妙用以及與對象庫程式設計的混搭
本人是不支援使用純描述性程式設計的,dp的使用應審時度勢且以實用的角度出發。前面也講到過了,一般情況下,描述性程式設計應用在對象庫程式設計無法完全滿足需求的時候,以替補的身份去出色完成少額的任務。但是要遵循一個原則,那就是不到必不得已(對象庫程式設計實在沒法解決),絕對不要去使用描述性程式設計,千萬要杜絕想使用了就随意使用的情況。這樣做有什麼好處?最大的好處就是可以使腳本一目了然進而增加了可維護性!當一段腳本中都是對象庫程式設計,突然有一行出現了描述性程式設計,那即使過了幾個月後再看腳本,我們也可以馬上明白,目前步驟是比較特殊的,是對象庫程式設計完成不了的。反之,如果不養成這個好習慣的話,那整個腳本的層次就會顯得非常亂,時間久了一定分不清哪些使用描述性程式設計的語句屬于沒必要範疇,而哪些屬于必要範疇。
接下來,就舉一些項目中需要使用到描述性程式設計的案例。
(1)百度首頁有很多相同的link控件,如“新聞”、“網頁”、“圖檔”等,全部添加到對象庫很麻煩,那麼該如何使用描述性程式設計完成?
首先,先來看下場景圖,如圖1-190所示。
一個首頁就有接近 20 個相同類别的控件(link),雖然不多,但是一個個添加也夠煩鎖的,既然它們是完全相同類型的控件,那麼使用描述性程式設計是一個上佳之選,下面來看這段腳本,看看是如何實作的:
執行腳本以後的結果就是在log視窗内寫8行true,傳回true就說明描述的對象存在了,也就說明描述性程式設計成功了,如圖1-191所示。
分析。
這段腳本首先用set将公共部分進行了提煉,這樣可以使重複的部分合為一個整體。然後完全還可以進行優化,是以,選擇使用with将所有會被複用的代碼提煉出來(這裡指baidu),這樣整個腳本就顯得非常清晰了。
這也是描述性程式設計常用情況之一的最基本的一個情況:同一個界面中出現很多個相同類别的控件元素。
(2)如果要同時操作浏覽器的多個視窗時,怎麼做?你想過嗎?
通常情況下,都隻需要在一個視窗中完成任務。如果同時出現兩個視窗的話,qtp就會出錯,因為qtp比對到了大于1個的視窗對象,是以它不知道究竟該對哪個具體對象進行操作了。是以,此時就要用以下這個方法,腳本如下所示:
使用以上代碼,qtp就能夠分辨出多個浏覽器視窗了,當然,也可以使用index或location屬性,大家可以嘗試一下。同時,也可以嘗試一下如何将指定的視窗關閉。
另外,當使用browser ("creationtime:=-1")的時候,表明目前有且僅有一個浏覽器視窗,當隻需要一個浏覽器的時候,可以使用這個方法來作為判斷依據,腳本如下所示:
(3)使用描述性程式設計通過周遊對象完成n個同類控件的操作。
假設有這麼一個場景,頁面中有幾百個輸入框,此時如果逐一将這幾百個對象添加到對象庫是不科學的,使用描述性程式設計則是一個明智選擇。但是,也不能逐一描述,因為效率同樣的低。在這種情況下,就可以用描述性程式設計來周遊頁面中的對象,進而最終完成艱巨的任務。百度的進階搜尋頁面就是一個比較典型的例子,頁面中有很多輸入框,如圖1-192所示。
現在要對這些輸入框做文章,在每個webedit中輸入“qtp自動化測試技術領航”這段字元串,實作腳本如下:
(4)qtp自帶的網上訂票系統是一個非常經典的描述性程式設計例子
衆所周知,在qtp裡自帶着一個網上訂機票的網站,也就是mercury tour。現在一起來看一下在訂票過程中何時需要使用描述性程式設計。
首先登入系統後,如果需要訂票的話,就要先搜尋航班,此時系統要求輸入訂票乘客的數量,假設在第一次寫腳本的時侯将passengers設定成了1,然後成功地完成了訂票。然後,需要參數化乘客數量來測試訂票系統,我們會發現qtp回放失敗了。其根本原因在于,乘客的數量已經變化了,導緻在訂票時需要輸入每個乘客的姓名,而在寫第一個腳本的時候,隻設定了一個乘客的姓名。乘客姓名的輸入框是随着乘客數量的變化而動态生成的,我們不可能從對象庫裡得到沒有添加過的對象(如果是100個乘客,那需要事先将100個乘客對應的姓名輸入框添加到對象庫裡,顯然這是不可取的)。是以,必須使用描述性程式設計來完成這個業務。現在,我們假設将乘客數量設定為2,如圖1-193所示。
然後來看一下設定單個乘客時的腳本如下所示:
然後到對象庫裡看看webedit控件,可以看到對象的屬性如圖1-194所示。
當系統對于發生多個firstname時,命名規則是passfirst0,passfirst1…依次類推。是以,我們現在隻要通過描述性程式設計就可以完成動态firstname與lastname的識别工作了。假設參數化的乘客數已經指派給intpassnum = 3,那麼在此,描述性程式設計腳本就該這樣寫:
再舉一個和這個經典例子差不多的案例,比如現在有一個訂書的網站,有一個輸入框可以輸入想要訂購的數量,輸入1就會出現1個輸入書名的文本框,代碼是:webedit("name:=book1");輸入2就會出現2個輸入書名的文本框,代碼是webedit("name:=book2")…同樣也是依此類推。像碰到這類情況,最好的解決方案就是描述性程式設計,代碼可以是:webedit("name:= book"& i)。
小結:以上這些都是對象庫程式設計搞不定或者不适宜搞定的案例。在真實的項目中一定還會有形形色色的案例,在此無法全部列舉。但是完全可以舉一反三,善加利用描述性程式設計,進而可以出色地輔助我們完成各種自動化測試需求。
1.7.5 終極對決—對象庫程式設計(op) vs描述性程式設計(dp)
關于對象庫程式設計和描述性程式設計的學習就要接近尾聲了。臨近結束之時,再一起來分析一下對象庫程式設計和描述性程式設計各自的優勢,也即知己知彼百戰百勝。
對象庫的優勢。
(1)可以通過complete word、“f7”等多個方式進行高效程式設計。這個特性描述性程式設計沒有。
(2)對象庫程式設計有一個比較好的特性,假設腳本中引用了同一個對象10多次,這個對象的名字之前取得不是太出色,項目經理要求改名。此時不需要改10多次,隻需要進入對象庫,對這個對象進行更名,腳本便會批量自動更新,很高效!這個特性描述性程式設計也沒有。
(3)對象庫程式設計不容易打錯字,因為有complete word,想打錯字都難。但是,描述性程式設計沒有complete word,是以,打錯字是家常便飯。關鍵是,對于一個新測試員來說,他不可能有敏銳的分析手段,往往因為這麼一個小錯别字會浪費很多時間。其實隻是一個錯别字而已,往往最後被誤解成腳本發生了錯誤,無論怎麼調試都看不出來。
描述性程式設計的優勢。
(1)不用維護龐大的對象庫,不過需要維護龐大的代碼。是以這算是優勢還是劣勢?請讀者感悟。作者在此提一句,其實在對象庫功能做得如此智能的情況下,維護好對象庫不難,隻要根據在“對象庫”那個章節中介紹的一些法則,如命名規範等就可以管理好對象庫。
(2)描述性程式設計可以完成一些特殊的需求(上一個小節的主講内容)。
最後的pk結果:對象庫程式設計獲勝!
1.7.6 總結
描述性程式設計的學習全部結束了,它是一個很好、很優秀的功能,但同時也是一把雙刃劍。最大的問題就是由于腳本無法維護導緻自動化測試項目的失敗。
通過本章的學習,希望讀者不光可以掌握描述性程式設計的技能,更應該了解它的缺陷,不要盲目崇拜“程式設計”這兩個字,開個玩笑的說:“描述性程式設計,不好惹!”
自動化測試的目的是使測試自動化起來,不是一種炫耀,本人也一再強調過:能做好自動化測試項目的自動化測試才是好的、成功的。是以,不到必不得已,請遠離“描述性程式設計”!
在對象庫程式設計和描述性程式設計的學習結束之際,也就意味着廣大新人讀者已經完全可以獨立去寫一些自動化測試腳本了,已經逐漸開始有能力成為一名“qtp自動化測試工程師”,已經徹底擺脫了錄制化的qtp,這是一個裡程碑!
知識點鞏固和舉一反三練習
素材:
title = browser("百度一下,你就知道").page("百度一下,你就知道").object.title
msgbox browser("百度一下,你就知道").page("百度一下,你就知道")._
webbutton("百度一下").getroproperty("value")
browser("百度一下,你就知道").page("百度一下,你就知道").link("關于百度").click
一、使用基礎方法描述素材中的代碼。
二、使用description.create方法描述素材中的代碼。
本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。