自動化測試異常處理與用例管理_第1頁
自動化測試異常處理與用例管理_第2頁
自動化測試異常處理與用例管理_第3頁
自動化測試異常處理與用例管理_第4頁
自動化測試異常處理與用例管理_第5頁
已閱讀5頁,還剩13頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、 .測試用例的前置條件和后置條件除 了第二點中談到的數(shù)據(jù)需要準(zhǔn)備外,在測試用例這個Level,必須有一些條件滿足,您才能開始執(zhí)行它。比如準(zhǔn)備一個初始設(shè)置條件下的IE 瀏覽器和已安裝過老版本該軟件的XP系統(tǒng)。這些可重用的準(zhǔn)入條件,可以考慮不作為特定用例的Step,而是把它提取出來,作為Setup Section或叫Pre-Condition。對于后置條件或Post- condition,往往我們用它來做一些處理或恢復(fù),比如在上面的取款例子中,如果我們要用一樣的重復(fù)測試,在正好取完所有金額,余額為零的情況 下,可以通過一些步驟或數(shù)據(jù)庫腳本重置余額。同樣,您為某個用例設(shè)置瀏覽器禁用了Cookie,執(zhí)

2、行完該用例后,是不是也是需要回復(fù)到默認(rèn)設(shè)置的狀態(tài) 呢?集中的把這些步驟整理成一個相對獨立的操作單元,具體用例中只要引用就可以了,這樣會便于對用例的理解和在多處復(fù)用。順便說一下,對于一些類似軟件運行環(huán)境的條件,比如安裝和配置測試中,需要3種操作系統(tǒng)和3種瀏覽器的組合等,我們可以把他放在Test Set這個Level上來,不用寫多個用例,只是在測試計劃和執(zhí)行的管理系統(tǒng)中作為測試集的一個環(huán)境參數(shù),恰當(dāng)?shù)乇磉_出來就可以。4. 常用業(yè)務(wù)操作(Knowledge Base)對于一個大型的應(yīng)用,比如銀行系統(tǒng),開發(fā)和測試工作是長期的,持續(xù)的一個過程,這樣的系統(tǒng)很適合引入自動化測試。它業(yè)務(wù)邏輯復(fù)雜,測試技術(shù)性要

3、求高,往往使用了不同廠商的工具和多種腳本語言(如Shell,Python等),也存在了很多可用的遺留腳本。這些完成一些預(yù)定業(yè)務(wù)操作的腳本單元,是可以直接借用的。為了在公司和產(chǎn)品層面,管理好這些可復(fù)用的資源,一種好的方式是給它們標(biāo)上號,如KB_PRJ01_Module02_XXX,集中管理起來,以后的用例中只要調(diào)用即可。舉 例來說,在銀行業(yè)務(wù)測試中我們,需要模擬和銀聯(lián)的接口,讓測試向外匯款,取得響應(yīng)信息,并保存結(jié)果,這可能是個復(fù)雜而底層的處理過程,對一般員工是不 需要,也沒有權(quán)限去深入掌握的。這時,將他們包裝成一個個Shell腳本或小工具,做好使用說明和統(tǒng)檔,在以后的項目測試中,只要調(diào)用就可以了

4、。如 此,可以大大提高各個有相關(guān)接口的模塊的自動化測試工作效率。根據(jù)以往工作中常見的一些問題,對于如何寫好測試用例(不僅針對自動化測試),做以下做幾點補充: 推薦 不推薦 將用例的容描述清楚,強調(diào)怎么操作,驗證什么,然后期待的結(jié)果是什么。 Copy需求和設(shè)計文檔中的容;描述成:什么條件下,邏輯會是怎樣。這樣對測試用例的閱讀和執(zhí)行人員,不具有可操作性。 期待的結(jié)果要寫具體,如:系統(tǒng)反應(yīng)是什么;結(jié)果數(shù)字是多少;用戶被帶到什么頁面;顯示什么成功信息;后臺或數(shù)據(jù)庫中該記錄的修改后結(jié)果是怎么樣的。 描述成:”驗證系統(tǒng)返回正確結(jié)果“;”頁面元素顯示跟SPEC一致“;”操作成功“等 比較抽象的說法。 業(yè)務(wù)邏

5、輯性較強的應(yīng)用軟件,做到以業(yè)務(wù)流為主線,來組織用例。 以頁面形式組織用例。 以Module、Function、測試類型、基本業(yè)務(wù)流、備選業(yè)務(wù)流的樹狀結(jié)構(gòu)形式,分層次組織用例;使用用例管理工具。 Word格式的扁平組織結(jié)構(gòu),不利于管理和閱讀。 用一個屬性字段,建立用例和Spec等文檔的某個章節(jié)間的映射。 無法和需求對應(yīng),以后難以計算 用例覆蓋率,測試執(zhí)行覆蓋率。 每個Module、Function、特定業(yè)務(wù)的一組測試用例,之間做到獨立、沒有耦合。 用例之間有依賴,無法做到:挑選30%的用例做回歸測試。 在時間和成本允許的情況下,盡量做到:用例粒度為“一種不同的操作,得到不同的結(jié)果,就單獨寫一個用

6、例“。 在用例中的操作步驟中,甚至期待結(jié)果中,仍然存在條件分支。 對于復(fù)雜的業(yè)務(wù)操作過程,如”一次順序的表單簽核過程“和”一次完整的信貸手續(xù)“,單獨增加一些貫穿整個業(yè)務(wù)流的大型測試用例。 對于一個長業(yè)務(wù)操作,只存在比較零散的細(xì)節(jié)用例。 將用例分優(yōu)先等級,便于在回歸測試時挑選核心業(yè)務(wù)或用戶操作密集的用例。 用例 沒有優(yōu)先級和重要程度的定義。 自動化測試用例設(shè)計的原則很多公司在實施自動化測試的過程中,往往會把所有的手工測試用例作為自動化測試用例,并且直接進行腳本的開發(fā)工作,甚至有些公司不寫自動化測試用例,直接想當(dāng)然地開發(fā)測試腳本,這些都是極其不規(guī)的做法,甚至很有可能是導(dǎo)致最后自動化測試項

7、目失敗的最大原因。那么問題就來了,為什么不能使用手工測試用例完全替代自動化測試用例呢?有以下幾點原因,同時也是自動化測試用例的設(shè)計原則 原則1:自動化測試用例的圍往往是核心業(yè)務(wù)流程或者重復(fù)執(zhí)行率較高的。 在選取自動化測試用例圍時,很多測試工程師或者上級領(lǐng)導(dǎo)可能心里會過分依賴自動化測試,會認(rèn)為自動化測試就應(yīng)該覆蓋所有的手工測試用例,自動化測試的 覆蓋率就應(yīng)該達到百分之百。其實恰好相反,這樣的想法往往會導(dǎo)致自動化測試最終失敗。在一些大型項目中,往往測試用例的數(shù)量會很龐大,而且如果遇到一些繁 雜的被測程序(特別是C/S架構(gòu)),腳本開發(fā)工作往往會相當(dāng)耗時間,并且很多測試用例甚至根本就不能通過

8、自動化來實現(xiàn)。舉些例子,現(xiàn)在很多公司自動化測試 都是剛起步,對自動化測試的了解程度只是停留在字面上,在公司對測試也不是非常重視的情況下,當(dāng)然不太愿意去花精力招一個具有自動化測試開發(fā)經(jīng)驗的工程 師,很多還是停留在使用工具的錄制回放功能來完成自動化測試。正是存在這樣的技術(shù)限制情況下,往往在實施中,會出現(xiàn)很多錄制回放不能解決的問題,測試工具 完全無法識別測試對象,無法識別一些特殊的加密測試控件。還有,如果項目的變更頻率,測試用例數(shù)量大的話,增加了后期的維護工作量等,都是造成最終失敗的 一些隱患。投入越大,損失越大。因此,往往我們會選取最核心的一些業(yè)務(wù)路徑或者是重復(fù)執(zhí)行率較高的一些手工測試用例進行自動

9、化測試,這樣能夠充分發(fā)揮出自 動化測試的優(yōu)勢。 原則2:自動化測試用例的選擇一般以“正向”為主。手工測試用例分正常情況和異常情況,在設(shè)計的時候,可能往往會去設(shè)計很多異常情況來驗證程序是否有Bug, 并且一個正常情況的測試用例往往會對應(yīng)幾十個非正常情況的測試用例,而每種異常情況的測試用例都會有各種各樣的預(yù)期結(jié)果。在自動化測試中,很多人喜歡將正 常情況稱為“正向”;反之,異常情況則稱為“反向”。下面,我們試想以下,如果將這些異常情況全部轉(zhuǎn)化、反應(yīng)到自動化測試腳本中,那肯定需要非常繁瑣的判 斷才能做到。這個對于自動化測試工程師來說,其現(xiàn)有的工作量還是今后的腳本維護量都是不可小視的。對于整個

10、自動化測試項目來說,如果每個異常情況都要寫進 腳本中,那真的是花了大價錢買一堆小東西,小東西真正能發(fā)揮大作用的畢竟很少。因此,真正在自動化測試項目實施中,往往會舍棄反向用例,個別比較重要的除 外。使每個東西都能發(fā)揮其最大的作用才是企業(yè)最想看到的。功能自動化測試主要還是用于回歸測試,回歸測試的目的就是保證新增功能后老功能是否能夠正常繼續(xù) 運作。而自動化測試則是讓測試人員從繁瑣又枯燥的重復(fù)手工測試中解放出來,這就是目的和目標(biāo)。原則3:不是所有手工測試用例都可以使用自動化測試來實現(xiàn)的。 這里糾正許多測試從業(yè)人員的一個錯誤觀念,剛接觸測試自動化的普遍都會認(rèn)為手工測試用例全部要轉(zhuǎn)化為自動化測試用例,但是

11、在真正實施的時候,卻發(fā)現(xiàn)很多 測試用例是自動化無法實現(xiàn)的,或者有些測試用例根本就沒有必要去自動化的。例如,有些用例會牽涉到硬件設(shè)備輔助的,最簡單的例子就是用例執(zhí)行過程中需要使 用刷卡機才能獲取卡號信息(如果有技術(shù)能力,當(dāng)然不排除自行開發(fā)接口供測試工具調(diào)用,但畢竟能有技術(shù)實力做到這一步的不多,能有這樣的重視程度的更不 多);再比如,有些測試用例是需要與合作機構(gòu)進行互動聯(lián)調(diào),聯(lián)調(diào)時是需要和對方實時溝通,以與根據(jù)具體情況給予響應(yīng)的,這些情況多數(shù)還是只能使用手工人為 地來完成。當(dāng)然,決定是否轉(zhuǎn)化為自動化測試,必須事先有一個規(guī)文檔來定義哪些是需要轉(zhuǎn)化為自動化測試哪些是不需要的,否則測試工程師就會不知所措

12、,沒有 一個標(biāo)準(zhǔn)。一旦有了這個標(biāo)準(zhǔn),自動化測試工程師就可以嚴(yán)格按照文檔里的流程去完成需要轉(zhuǎn)化部分的自動化測試用例的腳本開發(fā)工作了。原則4:手工測試用例可以不用回歸原點,而自動化用例往往是必須的。 很多有經(jīng)驗的自動化測試從業(yè)人員一定有這樣的經(jīng)歷,很多時候腳本寫完后,第一次執(zhí)行沒有任何問題,而第二次執(zhí)行時立刻就會報錯,原因就是沒有回歸原點。 所謂回歸原點就是執(zhí)行的測試用例最終需要恢復(fù)其在執(zhí)行前的初始狀態(tài),如果沒有回歸原點,就會把此腳本稱之為死腳本。舉個最簡單的例子,比如添加用戶功能, 我們都知道每個用戶名都是唯一的,當(dāng)寫完一個添加用戶的腳本之后,執(zhí)行第一次沒有問題,因為執(zhí)行前此用戶還不存在,但是當(dāng)

13、執(zhí)行第二次時,程序就會出現(xiàn)用戶 重復(fù)而報錯,此時這個添加用戶的腳本就失去了它的價值,在這種情況下,我們就需要在自動化測試用例的最后加上刪除這個用戶的步驟,這樣在下次執(zhí)行用例時就 不會出現(xiàn)用戶重復(fù)的情況了。當(dāng)然,除了回歸原點,還可以使用另一種方式進行,那就是初始化數(shù)據(jù),比如ATM機取款,假設(shè)需要執(zhí)行取款100元的操作,而銀 行卡余額是120元,當(dāng)測試腳本第一次執(zhí)行時可能沒有任何問題,但是第二次系統(tǒng)就會報余額不足,這樣就成為了死腳本,解決方案有兩種:一種是直接進行初始 化數(shù)據(jù),每次執(zhí)行用例之前都重置下余額(只需大于100即可);第二種方法可以在用例執(zhí)行前,先查詢下余額是否大于100,若大于等于則繼

14、續(xù),若小于則做 一筆充值100的操作,這樣即可解決。兩種方式可以看具體情況使用,數(shù)據(jù)初始化方便,但有時候初始化之后可能會影響到其他自動化測試用例的執(zhí)行,而第二種 方式相對在腳本上需要稍微花點功夫。究竟使用哪種方式還需要具體情況具體分析??傊趫?zhí)行自動化測試用例之前做好數(shù)據(jù)準(zhǔn)備,這也是自動化測試的關(guān)鍵步 驟。原則5:自動化測試用例和手工測試用例不同,不需要每個步驟都寫預(yù)期結(jié)果。 在手工測試用例的設(shè)計過程中,幾乎每一個測試步驟都有一個預(yù)期結(jié)果。但是,在自動化測試用例的設(shè)計中并不采用,在自動化測試用例中,只有準(zhǔn)備在測試腳本 中設(shè)置成檢查點的步驟才有預(yù)期結(jié)果,其他所有的步驟只將它看作一個步驟,這樣做

15、的好處是一目了然、目的明顯、層次分明,以后寫測試腳本直接跟著自動化測試 用例就行了。因為經(jīng)過前面的探討應(yīng)該已經(jīng)知道,自動化測試中并不是所有的東西都需要驗證的。所以,作者在前面的章節(jié)中也提到過,基本上手工測試用例多多少 少都要進行一些轉(zhuǎn)換的,就是因為它們之間的格式是不一致的。舉一個簡單的例子,假設(shè)需要設(shè)計一個注冊頁面的自動化測試用例,有10幾個表單 需要填寫,在手工測試用例中,每個表單的填寫都一定會有預(yù)期結(jié)果,因為它的確在檢查每一項是對了還是錯了,只是用的是你的眼睛在檢查而已,所以速度非常的 快,甚至你自己潛意識都忽略了其實你已經(jīng)檢查了。但是,在自動化測試中,我們知道如果你要檢查,那一定需要寫代

16、碼,如果每項都檢查,那代碼量有多大是可想 而知的,不是說做不到,只是這樣做根本不符合自動化測試的特點。所以,絕大部分時候,這些在自動化測試中可有可無的檢查,我們?nèi)俊安粰z查”,只當(dāng)做一個業(yè)務(wù)流程和步驟,是不需要設(shè)立預(yù)期結(jié)果的。難以對于UI樣式或UI邏輯進行斷言以上圖為例,有一個UI樣式類的缺陷(左側(cè)菜單樹的根節(jié)點“console”下面多出來一條虛 線)和一個UI邏輯類的缺陷(右側(cè)用戶列表只有一頁,但“下一頁”和“最后一頁”圖標(biāo)依然是可以點擊的,即沒有灰顯)。此類缺陷即使對于經(jīng)驗豐富、心思縝 密的測試人員,在人工測試時也是很可能發(fā)現(xiàn)不了的,并且在自動化測試過程中也很難進行斷言。即使存在上述問題,

17、測試腳本中是否有充分的斷言,依然是評判自動化測試有效性的一個重要指標(biāo)。但實施過自動化測試的人應(yīng)該都會有這樣的體會:“大部分?jǐn)嘌栽诖蟛糠智闆r下只是佐證軟件是運行正常的”。當(dāng)然,所有人都應(yīng)該是非常期待看到這樣的結(jié)果,畢竟誰也不希望每次回歸測試時都是用例大面積不通過。只是辛辛苦苦寫這些斷言語句的測試人員心里未免有些“小遺憾”。本系列上篇文章中談到“很多人一提到自動化測試腳本,馬上就想到需要提供錄制工具”,但如果換個角度思考,很可能就是“柳暗花明又一村”。在這里,我們同樣換個角度思考,假設(shè)我們的自動化測試主要目標(biāo)是為了證明軟件運行正常,那么我們會怎么做?筆者這邊的一個經(jīng)驗就是“按照完整的業(yè)務(wù)流程來組織

18、測試用例,只對少量、必要的關(guān)鍵點進行斷言”。以“租戶對虛擬化資源的申請使用”為例,來具體看看測試用例的組織方式:1. 新租戶注冊;2. 管理員登錄系統(tǒng),對注冊租戶進行審批,然后退出系統(tǒng);3. 審批后的租戶登錄系統(tǒng);4. 租戶申請所需要的虛擬化資源(比如,40G硬盤、2核CPU、2G存),然后退出系統(tǒng);5. 管理員登錄系統(tǒng),對租戶申請的資源進行審批,然后退出系統(tǒng);6. 租戶登錄系統(tǒng),在已申請資源的基礎(chǔ)上創(chuàng)建安裝指定操作系統(tǒng)的虛擬機;7. 斷言虛擬機是否創(chuàng)建成功;8. 租戶退出系統(tǒng);9. 管理員登錄系統(tǒng),刪除租戶;10. 斷言租戶之前申請的資源是否被完全釋放;11. 租戶再次登錄系統(tǒng),斷言是否無法

19、登錄;上述測試用例就是按照完整的業(yè)務(wù)流程進行組織,并且只對少量關(guān)鍵點(7、10、11)進行斷言,如果整個用例可以運行通過,就能證明這個業(yè)務(wù)是沒有問題的。另外還有一個值得考慮的現(xiàn)象,就是相對于自動化測試而言,一個優(yōu)秀的測試人員在人工測試時是如何判斷功能正確與否的呢?他不會死板的只盯著某幾個輸 入域的值,他一定還會同時關(guān)注頁面上所有數(shù)據(jù)的正確性、會更加關(guān)注業(yè)務(wù)流程是否正確、會更敏銳的發(fā)現(xiàn)頁面樣式或UI邏輯類的缺陷。為了兼顧“證明軟件正常運行”和“人性化的識別軟件缺陷”,一個優(yōu)秀的測試工具應(yīng)該考慮提供以下多種斷言機制。一、 控件級細(xì)粒度斷言即前面提到的最常見的斷言方式。在測試過程中,可以在任何位置增

20、加斷言腳本,來判斷頁面指定控件是否存在、控件顯示值是否為預(yù)期結(jié)果等。通常建議只對關(guān)鍵校驗點進行斷言。二、 頁面級粗粒度斷言通過對比前(之前測試通過)后(后續(xù)持續(xù)發(fā)布)版本在測試用例路徑和輸入?yún)?shù)一樣的情 況下,整個頁面容(包括截圖和數(shù)據(jù))是否嚴(yán)格一樣來做粗粒度斷言。通過頁面截圖進行斷言有兩個實現(xiàn)要點:首先要選擇一個合適的截圖方案(筆者推薦采用Selenium WebDriver提供的TakesScreenshot接口);其次需要提供圖片對比工具,以便測試人員可以一眼看出兩個版本頁面截圖的差異。下面是筆者在測試框架中實現(xiàn)的截圖自動化對比功能的實際效果。下圖中左側(cè)部分是“實際結(jié)果截圖”、右側(cè)是“預(yù)

21、期結(jié)果截圖”、中間部分是差異對比,測 試人員一眼便可看出其中的Bug:“表格行選中的翻頁緩存(在當(dāng)前頁選中幾條記錄,翻到下一頁再翻回本頁,需要保持之前的行選中狀態(tài))功能丟失了”。通過頁面數(shù)據(jù)進行斷言的實現(xiàn)方式相對簡單一些,首先要提取頁面上所有的數(shù)據(jù)(或文本),接著進行格式化,然后再自動化對比。 “頁面級粗粒度斷言”的特點與應(yīng)用場景如下:· 無需編寫任何斷言語句;· 需要能夠提供可用于自動對比的歷史正確版本,特別適用于可以持續(xù)構(gòu)建的項目;· 能判斷出UI樣式和UI邏輯類的錯誤;· 由于對比絕對精準(zhǔn),導(dǎo)致可能存在誤判,因此需要人工對差異圖片進行排查; 注由于

22、很多Web頁面都有漸入漸出、點擊時按鈕變色等很炫的效果,所以在兩次截圖的瞬間可能頁面的動態(tài)樣式是不一樣的,這就是所謂的“誤判”。筆者對 于一個“動態(tài)樣式”適中的項目采用這種斷言方式,統(tǒng)計結(jié)果表明誤判率在20%左右。· 鑒于回歸測試的時候,通常大部分用例應(yīng)該是可以通過的,所以“頁面級粗粒度斷言”的投入產(chǎn)出比非常占優(yōu)勢!三、 基于業(yè)務(wù)邏輯斷言在測試設(shè)計時把有依賴關(guān)系的用例一起執(zhí)行,如果某個步驟出現(xiàn)問題,即便不設(shè)置任何斷言語句,在當(dāng)前步驟或后續(xù)步驟的測試用例也會執(zhí)行失敗。下面以“增加、查詢、修改、刪除”這個最典型的流程來說明(如下圖所示)。假定在“增加”環(huán)節(jié)出現(xiàn)問題,那么我們的測試用例執(zhí)行

23、情況可能出現(xiàn)如下幾種結(jié)果:1. 如果在“增加記錄A”的用例中包含對是否增加成功的斷言,那么測試用例從“增加記錄A”開始出錯;2. 如果在“增加記錄A”中不包含斷言,而是在“查詢A”的用例中包含是否有查詢結(jié)果的斷言,那么測試用例會從“查詢A”開始出錯;3. 如果在“查詢A”中也不包含斷言,那么測試用例會從“修改查詢結(jié)果”開始出錯。所謂“基于業(yè)務(wù)邏輯斷言”,就是指上述第三種情況,其特點與應(yīng)用場景如下:· 無需編寫任何斷言語句,但測試設(shè)計要考慮業(yè)務(wù)邏輯順序;· 與“頁面級粗粒度斷言”相比,不需要提供可用于對比的歷史正確版本,通常適用于項目剛開發(fā)或樣式做整體調(diào)整等情況;·

24、 斷言錯誤的位置不精準(zhǔn),可能延后;· 執(zhí)行過程每一步都做截圖備份(通過Selenium WebDriver可以很方便的實現(xiàn)),可以非常有效的輔助定位準(zhǔn)確的出錯原因;· 鑒于回歸測試的時候,通常大部分用例應(yīng)該是可以通過的,所以“基于業(yè)務(wù)邏輯斷言”的投入產(chǎn)出比非常占優(yōu)勢!四、 自定義擴展斷言在人工測試時經(jīng)常有些操作結(jié)果的正確與否在當(dāng)前頁面無法做出判斷,需要到其它頁面甚至系統(tǒng)外部(比如,數(shù)據(jù)庫、輸出日志)獲取信息來做出判斷。以最常見的“基于數(shù)據(jù)庫進行斷言”為例,測試工具需要支持把斷言時用到“預(yù)期結(jié)果”和“實際結(jié)果”配置為對應(yīng)的SQL語句。以上介紹了從測試工具的角度可以提供的多種斷

25、言機制,在自動化測試過程中應(yīng)該根據(jù)項目實際情況,考慮采用上述多種斷言的組合,以彌補控件級細(xì)粒度斷言的不足。ASP.NET MVC集成EntLib實現(xiàn)“自動化”異常處理實例篇個人覺得異常處理對于程序員來說是最為熟悉的同時也是最難掌握的。說它熟悉,因為僅僅就是try/catch/finally而已。說它難以掌握,則是因為很多開發(fā)人員卻說不清楚try/catch/finally應(yīng)該置于何處?什么情況下需要對異常進行日志記錄?什么情況下需要對異常進行封裝?什么情況下需要對異常進行替換?對于捕獲的異常,在什么情況下需要將其再次拋出?什么情況下則不需要?合理的異常處理應(yīng)該是場景驅(qū)動的,在不同的場景下,采用

26、的異常處理策略往往是不同的。異常處理的策略應(yīng)該是可配置的,因為應(yīng)用程序出現(xiàn)怎樣的異常往往是不可預(yù)測的,現(xiàn)有異常策略的不足往往需要在真正出現(xiàn)某種異常的時候才會體現(xiàn)出來,所以我們需要一種動態(tài)可配置的異常處理策略維護方式。目前有一些開源的異常處理框架提供了這種可配置的、場景驅(qū)動的異常處理方式,EntLib的Exception Handling Application Block(以下簡稱EHAB)就是一個不錯的選擇。源代碼從這里下載本文已經(jīng)同步到How ASP.NET MVC Works?中目錄 一、通過指定Handle-Error-Action響應(yīng)請求 二、通過Error View顯示錯誤消息 三

27、、自動創(chuàng)建JsonResult響應(yīng)Ajax請求一、通過指定Handle-Error-Action響應(yīng)請求在正式介紹如何通過擴展實現(xiàn)與EntLib以實現(xiàn)自動化異常處理之前,我們不妨先來體驗一下異常處理具有怎樣的“自動化”特性。以用戶登錄場景為例,我們在通過Visual Studio的ASP.NET MVC項目模板創(chuàng)建的Web應(yīng)用中定義了如下一個簡單的數(shù)據(jù)類型LoginInfo封裝用戶登錄需要輸入的用戶名和密碼。 1: public class LoginInfo 2: 3: DisplayName("用戶名") 4: Required(ErrorMessage="請

28、輸入0") 5: public string UserName get; set; 6:  7: DisplayName("密碼") 8: Required(ErrorMessage = "請輸入0") 9: DataType(DataType.Password) 10: public string Password get; set; 11: 然后我們定義了如下一個HomeController?;?-GET的Action方法Index將會呈現(xiàn)一個用戶登錄View,該View使用創(chuàng)建的LoginInfo對象作為其Model。真正的用

29、戶驗證邏輯定義在另一個應(yīng)用了 PostAttrubute特性的Index方法中:如果用戶名不為Foo,拋出InvalidUserNameException異常;如果密碼不是“password”,則拋出InvalidPasswordException異常。InvalidUserNameException和InvalidPasswordException是我們自定義的兩種異常類型。 1: ExceptionPolicy("defaultPolicy") 2: public class HomeController : ExtendedController 3: 4: publi

30、c ActionResult Index() 5: 6: return View(new LoginInfo(); 7: 8:  9: Post 10: HandleErrorAction("OnIndexError") 11: public ActionResult Index(LoginInfo loginInfo) 12: 13: if (string pare(loginInfo.UserName, "foo", true) != 0) 14: 15: throw new InvalidUserNameException(); 16:

31、17:  18: if (loginInfo.Password != "password") 19: 20: throw new InvalidPasswordException(); 21: 22: return View(loginInfo); 23: 24:  25: Post 26: public ActionResult OnIndexError(LoginInfo loginInfo) 27: 28: return View(loginInfo); 29: 30: 上面定義的HomeController具有三點與自動化異常處理相關(guān)的地方:&#

32、183; HomeController繼承自自定義的基類ExtendedController,后者完成了對異常的自動化處理。 · HomeController類型上應(yīng)用了自定義的ExceptionPolicyAttribute特性用于指定默認(rèn)采用的異常處理策略名稱(“defaultPolicy”)。 · 基于 -POST的Index方法上應(yīng)用了HandleErrorActionAttribute特性用于指定一個Handle-Error-Action名稱,當(dāng)異常在目標(biāo)Action執(zhí)行過程中拋出并通過EHAB處理后,指定的Action會被執(zhí)行以實現(xiàn)對請求的響應(yīng)。對于我們的例子來

33、說,從Index方法拋出的異常被處理后會調(diào)用OnIndexError方法作為對當(dāng)前請求的響應(yīng)。 下面是代表登錄頁面的View的定義,這是一個Model類型為LoginInfo的強類型View。在該View中,作為Model的LoginInfo對象以編輯默認(rèn)呈現(xiàn)在一個表單中,表單中提供了一個“登錄”提交表單。除此之外,View中還具有個ValidationSummary。 1: model LoginInfo 2: <html> 3: <head> 4: <title>用戶登錄</title> 5: <style type="tex

34、t/css"> 6: .validation-summary-errorscolor:Red 7: </style> 8: </head> 9: <body> 10: using (Html.BeginForm() 11: 12: Html.ValidationSummary(true) 13: Html.EditorForModel() 14: <input type="submit" value="登錄" /> 15: 16: </body> 17: </html>

35、;通過HomeController的定義我們知道兩種不同類型的異常(InvalidUserNameException和InvalidPasswordException)分別在輸入無效用戶名和密碼是被拋出來,而我們需要處理的就是這兩種類型的異常。正對它們的異常處理策略定義在如下的配置中,策略名稱就是通過應(yīng)用在HomeController上的ExceptionPolicyAttribute特性指定的“defaultPolicy”。 1: <configuration> 2: <configSections> 3: <section name="excepti

36、onHandling" 4: type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" /> 5: </configSections> 6: <exceptionHandling> 7: <exceptionPolicies> 8: <add name=&qu

37、ot;defaultPolicy"> 9: <exceptionTypes> 10: <add type="MvcApp.InvalidUserNameException, MvcApp" postHandlingAction="ThrowNewException" name="InvalidUserNameException"> 11: <exceptionHandlers> 12: <add name ="ErrorMessageHandler" typ

38、e="MvcApp.ErrorMessageHandler, MvcApp" errorMessage="用戶名不存在"/> 13: </exceptionHandlers> 14: </add> 15:  16: <add type="MvcApp.InvalidPasswordException, MvcApp" postHandlingAction="ThrowNewException" name="InvalidPasswordException&qu

39、ot;> 17: <exceptionHandlers> 18: <add name ="ErrorMessageHandler" type="MvcApp.ErrorMessageHandler, MvcApp" errorMessage="密碼與用戶名不匹配"/> 19: </exceptionHandlers> 20: </add> 21: </exceptionTypes> 22: </add> 23: </exceptionPolicies&

40、gt; 24: </exceptionHandling> 25: . 26: </configuration>通過上面的這樣異常策略配置可以看到:我們使用一個自定義的名為ErrorMessageHandler的ExceptionHandler來處理拋出來的InvalidUserNameException和InvalidPasswordException異常,而ErrorMessageHandler僅僅是指定一個友好的錯誤消息,該消息一般會呈現(xiàn)給最終的用戶。運行該程序后一個用于登錄頁面會呈現(xiàn)出來,當(dāng)我們輸入錯誤的用戶名和密碼的時候,相應(yīng)的錯誤消息(在配置過ErrorMes

41、sageHandler設(shè)置的錯誤消息)會以如圖7-16所示的效果顯示出來,其實整個View是通過執(zhí)行Action方法OnIndexError返回的ViewResult呈現(xiàn)出來的。二、通過Error View顯示錯誤消息除了通過執(zhí)行對應(yīng)的Handle-Error-Action來呈現(xiàn)異常處理后的最終結(jié)果之外,還支持錯誤頁面的錯誤呈現(xiàn)方法。簡單起見,我們只是用名稱為Error的View來作為最終的錯誤頁面。為了演示基于錯誤頁面的呈現(xiàn)方式,我們按照如下的方式重新定義了ViewsShared目錄下的Error.cshtml。 1: model ExtendedHandleErrorInfo 2: 3:

42、Layout = null; 4: 5: <!DOCTYPE html> 6: <html> 7: <head> 8: <meta name="viewport" content="width=device-width" /> 9: <title>Error</title> 10: <style type="text/css"> 11: h3 color:Red; 12: </style> 13: </head> 14: <

43、;body> 15: <h3> 16: Html.DisplayFor(m=>m.ErrorMessage) 17: </h3> 18: <ul> 19: <li>Controller: Html.DisplayFor(m => m.ControllerName)</li> 20: <li>Action: Html.DisplayFor(m => m.ActionName)</li> 21: <li>Exception: 22: <ul> 23: <li&g

44、t;Message: Html.DisplayFor(m => m.Exception.Message)</li> 24: <li>Type: Model.Exception.GetType().FullName</li> 25: <li>StackTrace: Html.DisplayFor(m => m.Exception.StackTrace)</li> 26: </ul> 27: </li> 28: </ul> 29: </body> 30: </html>

45、;上面這個View的Model類型是具有如下定義的ExtendedHandleErrorInfo。它繼承自HandleErrorInfo,只額外定義了一個表示錯誤消息的ErrorMessage屬性。在上面的這個View中,我們將錯誤消息、異常類型和StackTrace和當(dāng)前Controller/Action的名稱呈現(xiàn)出來。 1: public class ExtendedHandleErrorInfo : HandleErrorInfo 2: 3: public string ErrorMessage get; private set; 4: public ExtendedHandleErro

46、rInfo(Exception exception, string controllerName, string actionName, string errorMessage) 5: : base(exception, controllerName, actionName) 6: 7: this.ErrorMessage = errorMessage; 8: 9: 當(dāng)利用EntLib的EHAB對從Index方法中拋出的異常進行處理后采用錯誤View的方式來響應(yīng)請求,我們需要按照如下的方式將應(yīng)用在該方法上的HandleErrorActionAttribute特性注釋掉。 1: Exceptio

47、nPolicy("defaultPolicy") 2: public class HomeController : ExtendedController 3: 4: /其他成員 5: Post 6: /HandleErrorAction("OnIndexError") 7: public ActionResult Index(LoginInfo loginInfo) 8: 9: /省略實現(xiàn) 10: 11: 再次運行該程序并分別輸入錯誤的用戶名和密碼后,默認(rèn)的錯誤View(Error.cshtml)將會以如下圖所示地效果把處理后的異常結(jié)果呈現(xiàn)出來。三、自動

48、創(chuàng)建JsonResult響應(yīng)Ajax請求用于實施認(rèn)證的Action方法Index可以通過普通的 -POST的形式來調(diào)用,同樣也可以通過Ajax請求的方式來調(diào)用。對于Ajax請求來說,我們最終會將通過EntLib處理后的異常封裝成如下一個類型為ExceptionDetail的對象。如下面的代碼片斷所示,ExceptionDetail具有與Exception對應(yīng)的屬性設(shè)置。最終根據(jù)拋出異常對象創(chuàng)建的ExceptionDetail對象會被用于創(chuàng)建一個JsonResult對象對當(dāng)前Ajax請求予以響應(yīng)。 1: public class ExceptionDetail 2: 3: public Exce

49、ptionDetail(Exception exception,string errorMessage=null) 4: 5: this.HelpLink = exception.HelpLink; 6: this.Message = string.IsNullOrEmpty(errorMessage) ? exception.Message : errorMessage; 7: this.StackTrace = exception.StackTrace; 8: this.Type = exception.GetType().ToString(); 9: if (exception.Inne

50、rException != null) 10: 11: this.InnerException = new ExceptionDetail(exception.InnerException); 12: 13: 14:  15: public string HelpLink get; set; 16: public ExceptionDetail InnerException get; set; 17: public string Message get; set; 18: public string StackTrace get; set; 19: public string Typ

51、e get; set; 20: 當(dāng)客戶端接收到回復(fù)的Json對象后,可以通過檢測其是否具有一個ExceptionType屬性(對于一個ExceptionDetail對象來說,該屬性不可能為Null)來判斷是否發(fā)生異常。作為演示我們對Action方法Index對應(yīng)的View進行了如下的改動。 1: model LoginInfo 2: <html> 3: <head> 4: <title>用戶登錄</title> 5: <script type="text/javascript" src="Url.Content

52、("/Scripts/jquery-1.6.2.js")"></script> 1:  2: <script type="text/javascript" src="Url.Content("/Scripts/jquery.unobtrusive-ajax.js")"> 1: </script> 2: <script type="text/javascript"> 3: function login(data) 4: if

53、 (data.ExceptionType) 5: alert(data.Message); 6: 7: else 8: alert("認(rèn)證成功"); 9: 10: 11: </script> 6: </head> 7: <body> 8: 9: AjaxOptions options = new AjaxOptionsOnSuccess = "login" 10: 11: using (Ajax.BeginForm(options) 12: 13: Html.EditorForModel() 14: <input

54、 type="submit" value="登錄" /> 15: 16: </body> 17: </html>如上面的代碼片斷所示,我們通過調(diào)用AjaxHelper的BuginForm生成了一個以Ajax形式提交的表單。表單成功提交(服務(wù)端因?qū)伋龅漠惓_M行處理而返回一個封裝異常的Json對象,對于提交表單的Ajax請求來說依然屬于成功提交)后會調(diào)用我們定義的回調(diào)函數(shù)login。在該JavaScript函數(shù)中,我們通過得到的對象是否具有一個ExceptionType屬性來判斷服務(wù)端是否拋出異常。如果拋出異常,在通過調(diào)用al

55、ert方法將錯誤消息顯示出來,否則顯示“認(rèn)證成功”。我們再次運行我們的程序并分別輸入不合法的用戶名和密碼,相應(yīng)的錯誤消息會以對話框的形式顯示出來,具體的顯示效果如下圖所示。對于一個新項目,QA通常會首先為新特性創(chuàng)建手工測試用例,為了之后維護方便,也通常將這些用例存放在一Excel表或者一個專門的測試用例管理 系統(tǒng)里。而在項目進行過程中或之后,具備自動化測試能力的QA團隊會將手工測試用例轉(zhuǎn)化為代碼,加入套件(Suite)中,用于之后的回歸。以往我們認(rèn)為手工測試用例與自動化代碼之間存在聯(lián)系,但并不緊密:· 手工測試用例文檔很容易閱讀,可以幫助學(xué)習(xí)業(yè)務(wù),但因為維護不夠靈活,很難跟上快速的變

56、化。依賴手工測試用例對項目進行回歸又是與其痛苦的。· 自動化測試代碼可以很明顯的提升效率,但不容易閱讀。因為人們通常缺少更新代碼注釋的動力(沒什么外人會用到,老鳥又不依賴它),久而久之我們不知道那一堆自動化用例究竟測了些什么,導(dǎo)致通過率逐步走低,又無人維護。自動化測試最終土崩瓦解。這似乎是一種宿命般的失敗。有些團隊希望建立自動化測試體系,卻從一開始就遇到類似的問題,導(dǎo)致進展緩慢,無法持續(xù)向老板秀出效果,最終又退縮回原點。原因是什么?怎么去破解這個困局呢?1. 用例文檔不應(yīng)該與自動化代碼分離,而應(yīng)存在于代碼中,隨著代碼的變化而與時更新。2. 用例文檔應(yīng)該簡潔,可以自我組織與管理,并以一種清晰的結(jié)構(gòu)被展現(xiàn)和分享。3. 自動化測試用例的運行歷史應(yīng)該被測量和記錄,數(shù)據(jù)可以集中形成幾個直接清楚的度量指

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論