qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          做了7年手工測試迷茫了怎么辦?——給你的建議


          在新浪微博上有個朋友問到這個問題:“有多少是測試年限在7年以上但還仍然在做大量手工測試的。。。。,請朱老師給指導一條明路”,限于微博140的限制,我還是在blog中來分享一些我的觀點:

             手工測試工作并不比自動化測試設計,工具使用或開發簡單很多。你可以每年反思總結自己在測試分析的方法及能力上——減少測試對象遺漏,測試設計的方法及能力上——測試深度和去冗余,取得了什么進步,這就是你每年的努力提升方向。 自動化和工具畢業生都可以快速掌握,但如何設計一套漏測少,冗余少的測試用例框架則需要你豐富的手工測試經驗為基礎;如何設計一套能縮短研發進度保障測試質量的測試策略需要豐富的手工測試經驗為基礎。我03年就開始開發自動化測試框架(可以讓功能測試人 員只需要會腳本的if  for就可以完成自己的自動化測試腳本),一行一行寫的,相比國內目前大多數搞自動化測試的人算走得早的吧,07年時還參與給某大型IT廠商(測試有 400人當時)進行自動化測試咨詢(自動化測試框架以外的自動化測試相關經驗)。08年底出版的《軟件測試精要》一書中所提到的一些自動化測試的部分經驗在2010年的時候還被華為內部某些專職自動化測試工作人員提煉總結和傳播,內部下載量上百。我從03年唯自動化測試工作論,到后面慢慢淡化,逐漸從事了其他測 試類型的工作后我發現在測試領域自動化測試的重要性沒我想得那么高,也沒那么關鍵后,從08年起我完全離開了自動化測試領域,并發現了更多有價值更有意義 更有挑戰性的測試技術創新專題。如果關注我的blog,我的新浪微博會發現這幾年我分享的測試技術和經驗都是非自動化的,現在我還在路上。要知道測試的根 不是自動化,而是質量,在質量這一塊手工測試經驗人員是大有可為,也只有依賴你來大有可為,自動化測試的同事搞不定質量,也無法全局角度整體來提升效率, 自動化測試提升的效率從整個研發周期和測試周期來看,只能算是局部優化。搞好測試策略,搞好用例冗余也都能整體提升測試效率。

          posted @ 2011-10-10 10:08 順其自然EVO| 編輯 收藏

          測試用例設計心得

            一個好的測試用例是每個人都能執行的測試用例,不管你是否是測試人員,不管你是否了解整個軟件的工作流程,你都能順利的執行完測試用例,并對這個測試用例覆蓋到的功能點有了大概的了解。

            好的測試用例的設計相當了軟件開發中 的詳細概要設計,要寫出好的測試用例首先要對所測試的軟件很熟悉,熟悉軟件的每個功能點和系統的整個業務流程。其次,對整個測試用例有個好的規劃,理清主 線,功能點的在哪個地方被覆蓋都是需要考慮的。最后,需要良好的心態,寫測試用例是個繁瑣的過程,測試用例不是隨隨便便就能寫出來的,好的測試用例更需要 你在寫的過程中不斷去理清思路,并把每個功能點都恰當的寫進去。

            測試用例的規劃:

             用例的規劃非常的重要,它決定整個測試用例的思路、風格、覆蓋率。即對整個測試用例的成敗都有直接的響。對測試用例的規劃我個人總結出兩條思路:一條是 用例的線性規劃,另一條是功能點覆蓋型。這兩條思路的側重點各不相同,各有優缺點。線性的測試用例的要點是在理清每一條思路,即以業務線和流程線為主,每 一條線都是一個流程,然后把功能點穿插到每條線里去。把每條業務流程比作豎線,功能線比作橫線,那么功能點就是橫線和豎線的節點,這樣整個用例就是一張大 網,我們可以隨時向網中添加橫線或豎線,使得覆蓋率不斷增加,“漏網之魚”越來越小。

            另一種思路是功能點覆蓋型。在設計之前把要整套軟 件的功能點理清楚,這當然是非常的難的。但我們可以參考系統設計的功能流程圖,軟件的需求來進行分析和提取。還有一點就是測試人員的經驗來完善所需要的功 能點。這種思路的重點是把每個功能點都要在設計中體現出來,以功能點覆蓋為主,不管工作的業務流程。也就是說是按照各個功能模塊進行劃分的,分模塊進行用 例的設計。

            兩種思路相輔相承,各有各的優點。在實際的執行過程中,有時以業務流程來編寫比較容易,有時以功能模塊編寫比較容易。一個是以線為主,一個是以塊為主。

            測試用例的設計:

             規劃好測試用例的整體思路之后,就是測試用例的具體設計設計了。用例的設計的格式主要由測試環境,準備數據,前置條件,用例ID,預期輸入值,期望輸出 結果,測試執行結果和優先級等幾個部分組成。其余的還有一些統計頁,打印輸出的模板等。個人認為用excel設計比較簡便,excel可以有多個頁面,一 個頁面為統計測試結果和用例維護,一個為測試用例的主頁面,還有一個頁面可以放一些打印后的模板。這樣的設計有利于用例的維護。

            用例的預期輸入值和操作步驟是用例設計最重要的部分。設計好這兩個部分對經后測試用例的執行至關重要,特別是操作步驟的描述,要描述清楚每一步的操作步驟,這樣才能讓測試的執行者準確操作,不會產生歧義。用例所寫的每一句話都應該清晰的,沒有歧義的,否則就會出現用例維護時,其他測試人員看不懂你寫的是什么,測試用例執行的時候,看著很費力,達不到文中剛開始的要求。

            測試用例的維護:

             每個測試用例都要在經后執行的過程中去維護修改,使得測試用例的覆蓋率不斷提高。特別的測試用例的第一個版本時,需要維護的量是非常大的。我們可以邊測 試邊修改測試用例,也可以根據需求添加測試用例。每維護一次測試用例,就必修記錄下你修改的內容,以便于經后的閱讀和別人的維護。

            以上是我近期對于測試用例設計的理解,也是我近期工作的一個總結和體會,測試用例設計是一門高深的技術,也是軟件測試的重要組成部分,我們需要經驗來不斷提升用例的質量,設計出好的測試用例。

          posted @ 2011-10-10 10:06 順其自然EVO| 編輯 收藏

          淺談功能測試用例

          淺談淺談,各位都是測試用例設計方面的高手,本篇只是拋磚引玉,分享下我在測試過程中對測試用例設計和執行的一些感悟,也希望大家能有更好的觀點分享。

             首先是測試用例數據的來源,測試用例中的數據來源于需求,規范的需求人員會將用戶的準確信息匯總傳達給項目組的開發和測試人員(當然需求不準確是另一回 事),測試人員需要驗證的是開發的實現是否符合需求的預定目標。在項目開始的時候,開發人員著手設計框架和編碼,我們測試人員則排計劃和準備測試用例。剛 開始的時候覺得沒有需求文檔一切行動就像失去目標一樣。有時需求文檔確實跟不上進度,測試人員是不是就不用工作等 著呢?完全不是。其實測試人員獲取該產品的詳細信息有很多渠道,文檔只是一種其中一種文字化、實例化的方式,比較規范。測試人員完全可以和開發、團隊 Leader溝通、交流,將自己對這個系統的含糊不清的地方一一明確,這樣既可以彌補需求文檔不足帶來的不便,也加深測試人員對該系統的理解。對于需求文 檔有遺漏的地方,測試人員可以通過需求評審(由客戶、需求、開發、測試一起討論)進一步明確需求。

            其次是編寫用例了。個人編寫用例的習 慣是用例能夠覆蓋這個系統的功能點即可。用例設計的元素一般由ID、名稱、所屬功能模塊、測試前置條件、輸入數據、執行步驟、期望結果和備注組成,當然為 了規范執行,一般情況下還會加上執行人、執行時間和執行結果。譬如設計一個創建對象或者子節點的用例,個人在測試步驟中只會寫“正常登陸系統后,點擊創建 對象功能,輸入對象名稱,提交保存。”期望結果就是對象能夠準確無誤的創建。這樣一看,好像少了點東西,對,邊界值檢查(包括空值檢查、最大值和超過最大 值檢查以及特殊字符檢查甚至同名檢查)。個人覺得邊界值檢查的方法確實好,能夠發現很多缺陷(前人總結的真理)。不過經過權衡后,我還是沒有將這些譬如 “輸入超過20個字符檢查”、“不輸入任何值檢查”、“輸入相同名稱檢查”等字樣寫在用例里。為什么?

            聲明一下,我并不是反對用例寫的 很詳細,我只是覺得上述內容填寫(又叫過度設計)對測試用例來說沒有必要,有點本末倒置。一來簡介版的用例可以很小,很方便維護,同時后續需求變更后很容 易修改甚至不用修改;二來給用例執行者最大的自由(我不反對將編寫該用例時自己想到的閃光點寫在里面),對于熟練的測試工程師來說,看到輸入框的第一反應 就是不輸會怎么樣,超過了會怎么樣,不滿足你的要求你會怎么樣,可能是自然反應吧(我就是這樣,已經掉進這個溝里了),對于新手,我可能會加一行“注意邊 界值”,可能做我的新手可能比較“倒霉”哈,我一不會告訴你用例設計的方法,二不會告訴你用例執行思路,前者我認為是有志干這行的必修課,必須自己主動掌 握,我僅能帶你入門而已,至于后者則靠自己不斷測試不斷總結,每個人都不一樣,找到那個最適合自己的。還有一個不好的地方就是太詳細的用例給人的感覺就是 我不需要思考了,反正設計者已經想得很詳細了,導致編寫用例的時候絞盡腦汁,執行的時候完全可以被程序替代了。那樣也很難發現這個系統的隱藏的缺陷了。當 然對于在設計階段就想的很詳細的用例來說,不會因為測試人員的疏忽而導致潛在缺陷被遺漏,畢竟用例規范了測試人員的行為。

            用例編寫過程中不明白的問題可以先記錄下來,在用例編寫完成后,將所有不明白的地方匯總,提交需求確認,待確認后補充對應的內容。

            測試人員的工作是規范別人(需求、開發)的工作,我們自己的工作也必須規范,必須接受項目組其他人員的檢查,用例評審就是一個很好的方式,需求、開發和測試在一起討論達成最后的結果。測試人員負責修補其中不滿足的地方。

             接下來就是執行用例的習慣了,個人喜歡在執行之前通讀該功能模塊的所有用例,然后統計下需要測試的功能點,對執行的順序初步排序,這樣可以能提高效率, 不至于顧此失彼。譬如有6個用例,分別是對對象的增、改、刪和對對象關系的增、改、刪,編寫用例時的一般按照這個順序下來,執行的時候如果這樣的話那明顯 增加了工作量,改成對象的增、改完成后執行對象的關系,關系執行完成后刪除對象。既完整的執行了用例、測試了功能,又能做到效率最大化。

             記得一位資深的工程師說過:在一個產品的迭代兩輪過后,不加入新功能的情況下,僅憑用例是很難發現問題的。而實際過程中也確實如此,正是有鑒于此,個人 比較傾向測試用例只要設計的能夠完整覆蓋系統的功能點即可,至于新手的執行的問題,測試用例是為了規范測試人員的工作,將無限的測試工作有限化,并且方便 管理和復用,好像并不具備新手入門手冊這個功能(可以通過其他方式解決,不必在測試用例中過分遷就他們)。

            權且一家之言,不對之處歡迎討論。

          posted @ 2011-10-10 10:00 順其自然EVO| 編輯 收藏

          淺說測試用例----給測試新手的

           在此之前我搜集一些關于測試用例的知識,后來在我們的QQ群里專門定了一期討論,來探討測試用例,畢竟這是一個很大的話題,很難做到面面俱到,但我會盡量全面,用通俗的語言來說測試用例。

          -------------------------------------------------------------------------------------------------------------------------

            注:我們這里要說的測試用例指功能測試用例。

            一、什么是測試用例?

            測試用例是為某個特殊目標而編制的一組測試輸入、執行條件以及預期結果,以便測試某個程序路徑或核實是否滿足某個特定需求。

            通俗的講:就是把我們測試系統的操作步驟用按照一定的格式用文字描述出來。

            二、寫測試用例有什么好處?

            理清思路,避免遺漏

            這里是我們認為最重要的一點,假如我們測試的項目大而復雜,我們可以把項目功能細分,根據每一個功能通過編寫用例的方式來整理我們測試系統的思路,避免遺漏掉要測試的功能點。

            跟蹤測試進展

            通過編寫測試用例,執行測試用例,我們可以很清楚的知道我們的測試進度。

            歷史參考

            在我們所做的項目中,也許會有很多功能是相同或相近的,我們對這類功能設計了測試用例,便于以后我們遇到類似功能的時候可以做參考依據。

            重復性

            我們測試一個系統不是一個人測一遍就算測完的,需要多人反復的進行測試,那么我們就需要測試用例來規范和指導我們的測試行為。

            告訴領導,這事俺干過,不然別人怎么知道你測沒測,測的全面不全面,拿測試用例給他們看唄!俺就是照著這個干活,呵呵!

            三、測試用例的方法

            好吧,咱知道啥是測試用例了,也是知道為什么要寫測試用例了,那到底應該怎么寫?無從下手啊。我們在寫測試用例之前,先學習幾種方法,它是我們寫測試用例的指導思想。

            1、等價類劃分

             在某個輸入域的子集合,在該子集合中,各個輸入數據對于揭露程序中的錯誤都是等價的。假如有一個輸入框要求輸入1-10000個數,我們不可能用每一個 數去試,我們輸入5 和輸入6去驗證和揭露輸入框的錯誤可以看做是等價的。那么這個時候我們就可以隨機的抽取一些數據來進行驗證。如:10 、99、7777......

            等價類分:有效等價類和無效等價類

            輸入框要求輸入1-10000的數

            有效等價類:可以輸入1-10000之間的數來驗證,如:2、5、99、8495......

            無效等價類:可以輸入1-10000之外的任意字符驗證,如:20000、字母、下劃線、特殊符號、空格、回車.....

            2、邊界值

            邊界值是對等價類的補充,測試工作經驗告訴我們,大量的錯誤是出在輸入輸出的邊界價上。我們還拿上面的例子,一個輸入框要求輸入1-10000之間的數。我們要測它有沒有超出這個范圍,如:0、-1、-2、1000、10001.....等等,來判定是否超出了我們的范圍。

           3、因果圖

            因果圖方法最終生成的就是判定表,它適合于檢查程序輸入條件的各種組合情況。舉個例子:原因:A=0,B=0,結果我就可以判定:A=B。確切 的說他是一種因果關系思想。它會無形中指導這我們的測試。當然了,我們為了以免遺漏,可以把系統中的因果關系用圖畫出。不過系統大而復雜的話就是個體力活 了。呵呵。

            4、錯誤推測法

            基于經驗和直覺推測出系統可能存在的錯誤,從而有針對性的設計測試用例的方法。

            5、其它

            設計測試用例的方法有很多,我們常用就上面幾種,其它的方法還有:狀態遷移圖、流程分析法、正交驗證法等等。

            四、測試用例的格式與要素

            一個測試用例應該包括:編號,標題,測試場景,測試步驟,預期結果。

            當然還可加入一些它選項,如:優先級、測試階段....

            注:上面的格式取自《微軟的軟件測試之道》,它并不一定適合你,我只是讓大家對測試格式有個了解。

            關于測試用例的存放管理:

            1、項目管理系統自帶的用例管理,一般用例會與項目掛鉤,有固定的格式,搜索、修改等功能,使用起來非常方便。如:禪道項目管理、QC、bugfree 等等都帶的有用例管理功能。

            2、通過world\Excel文檔形式管理,這樣的好處就是自己定義測試用例的格式。

            -----------------------測試用例例子--------------------------------------------------------

            基礎知識了解的差不多了,下面來看一個具體的測試用例。我們會有更深刻的認識。

            注:這不是一個完整的測試用例,格式也不是固定必須這樣的,你們可以根據自己的需求編寫設計測試用例。

            ------------------------------------我們還需要知道的,關于測試用例的-------------------------------

            一、我們在什么時候可以設計測試用例?

            當根據客戶的需求整理出項目需求分析文檔時,我們就可以根據需求文檔來編寫測試用例了。但是,一般我們(國內大多小公司)項目需求文檔都非常“簡陋”,所以,很難根據需求文檔設計測試用例。

            我們只有等到項目開發人員把項目開發出來,給我們系統文檔、部署環境、數據庫結構(如果系統牽涉到數據庫的話),我們根絕這些文檔來設計測試用例。

            二、測試用例的評審與更新

            我們設計的測試用例設計完成之后,是否完整?是否符合系統?符合客戶要求?對用例做一個評審是必不可少。關于評審的方式,不同的公司有不同的流程。

            我們編寫的測試用例也不是經過評審之后就不變了,隨著需求的變更、功能的改進,測試用例當然也需要更新和變動。

            三、什么情況下不適合寫測試用例

            文件時間

            如果一個功能我很快就測試完了,而且只需要測試一遍,但我們設計測試用例時卻比較麻煩,花時間也長。這個時候就沒必要編寫測試用例了。

            需求變動大且頻繁

            需求的功能變動非常頻繁,而且變動很大,之前編寫的測試用例根本沒法使用,必須要重新編寫,這個時候也沒必要去設計測試用例了。

            項目時間不允許

            這一項是不太厚道的做法,如果不是急需交付客戶的話,盡量不要這樣做;當然了,如果只是給客戶展示或試用,可以在之后進行補充和完善測試用例。

            不要編寫不完整或別人看不懂的測試用例,那樣就沒有意義了。

            ==========================================個人閑聊內容,歡迎指正===================================

            四、停止軟件測試的標準。

            語句覆蓋最低不能小于80%,測試需求覆蓋率達到100%,測試用例覆蓋率達到100%,一、二級缺陷修復率達到100%,三、四級修復率達到80%。

            (上面一句是再網上找的,不是標準,只是個參考)

            bug等級:

            一級:非常嚴重的bug
            二級:嚴重的bug
            三級:一般性的bug
            四級:建議性問題

            五、關于探索性測試

            完全的執行測試用例時一件非常枯燥的事情,個人在執行測試用例時會做一些,其它的非常規性的操作,看系統是否會有相應的處理和提示。我的一部分bug就是再這種非常規操作下發現的。

            當然了真正的探索性測試需要對產品的深入了解,以及軟件開發技術有一定的深度和寬度。姑且把我們的探索性測試看成是瞎搗鼓吧!呵呵。

            六、交叉測試

            有木有發現,當我們第一遍測試系統時,會非常認真,但要我們測試第二遍時,我們不愿意像第一次那樣認真的去測了,這不能說明我們不負責,而是每個人都有的心理現象。這個時候,我們可以和其它測試人員交換功能來測試,提高效率,而且更容易發現問題。

            七、測試的目的

            1、我們讓它做的它必須會做。

            2、我們不讓它做的它必須不會做。

            可能你會發現有附加功能的時候,就是客戶沒有要求,我們加了這樣的功能,可能加了這點功能系統看上去會更好。這時怎么辦?算問題么?

            作為開發人員,中規中矩的做東西最好,如果真的有非常好的功能要加的話,需要和客戶溝通,然后寫到需求里。畢竟多一點功能多一點風險。呵呵

            作為測試人員,凡是不符合需求文檔的都需要當問題點提出。責任分明,以免后續麻煩。

            ----------------------------------------------------

            修改:

            1、測試用例的格式的要素,去掉“實際結果”

            2、關于測試方法“等價類劃分”的解釋。

            謝謝“zdd”朋友的糾正。:)



          posted @ 2011-10-10 09:50 順其自然EVO| 編輯 收藏

          各國測試用列分析

            作為黑盒測試的一個重要階段,功能測試毋庸置疑是不可缺失的。功能測試的相關話題很多,無論是測試的形式,例如手動測試和自動化測試,還是測試方法,例如數據驅動和關鍵字驅動,都有大量的研究文章。我這篇博文里卻打算從國別不同的角度來討論一下功能測試的差異,原創文章可能有一些謬誤的地方,請讀者指摘。

            日式循規蹈矩

            日本人給世界其他民 族的印象是做事認真嚴謹,對待問題一絲不茍,犯了錯誤按嚴重程度該下跪的下跪,該剖腹的剖腹。他們的這種一貫行事方式也帶到了軟件行業,而軟件行業的摩爾 定律,技術的日新月異,代碼、框架的多變,都似乎與他們的性格格格不入。日本制造的東西一向以堅固耐用著稱,給我映像最深的一個細節是,在日本工作的時候,發現他們的垃圾袋居然都堅固無比,用來逛超市買東西拎重物也是屢用不壞。然而,對于遵從摩爾定律的計算機行業來說,投入大量的精力來盡可能的發現bug以及解決問題是否很值,這真的是有待商榷的問題。

            但,話雖如此,日企采用的測試用例的設計方法還是非常值得我們學習的,這其中又首先要提一下要因分析法(網上有些說法把魚骨圖等同于要因分析法,我并不贊同此說,后面會有詳述)。

            要因分析法的精髓在于,以產品的某一特性為因子,以這個特性的不同表現(根據等價類劃分、邊界值分析等方法)為狀態,一一列舉后,采用二維組合的方式來確定測試用例。

            下面我舉一個簡單的例子“我打算從南京去北京”來說明。

          表1

             這即是一張簡單的要因表,值得注意的是,因子和狀態的確定是必須規定范圍的,而這個范圍在這個例子中則為“正常人的思考”范圍。譬如說,“交通方式”我 沒有寫“步行”,因為這不符合常人從南京去北京的思考方式,當然有人為了挑戰吉尼斯紀錄,這里非要采用步行方式從南京前往北京,那么狀態里添加這項顯然是 可以的。

            此外,因子和狀態的另一個隱性的確定方針為詳細度,這個度如何把握,我們可以從下表來理解:

          表2

            表2將表1的“交通方式”進一步細化,此時狀態的選擇將進一步增多。如果要求詳細度更加提高,例如因子為“動車”,那么可以加上狀態為“一等座”和“二等座”,這種組合很靈活,取決于我所需的詳細級別。

            要因確定之后,便是組合,以表1所列要因為例,二維組合有下列共18種:

          飛機-晴-白天,飛機-雨-白天,飛機-雪-白天,飛機-晴-夜晚,飛機-雨-夜晚,飛機-雪-夜晚
          火車-晴-白天,火車-雨-白天,火車-雪-白天,火車-晴-夜晚,火車-雨-夜晚,火車-雪-夜晚
          汽車-晴-白天,汽車-雨-白天,汽車-雪-白天,汽車-晴-夜晚,汽車-雨-夜晚,汽車-雪-夜晚

            對于表2來說,二維組合則有2*4*2*3*2=96種,貌似有點多,當然你想分析的越詳細,那么組合數量自然會相應的增加。

             回到表1得出的18種用例,假如我的通過條件是從南京到北京的時間越短越好,在實際的外界環境下(例如晴天,預期花費有限額),這18個用例中,就會出 現有的測試通過,有的測試失敗的情況了。在不同的實際外界環境下,測試通過的情況還會發生變化(例如下雪天,飛機會發生班次延誤)。

            要因分析法的好處在于“事無巨細,滴水不漏”,壞處在于過程“繁瑣冗長,枯燥乏味”。即使如此細致的要因分析,依然存在一定的用例遺漏的風險, 這個風險來自于對因子和狀態潛在的考慮不周。隨著詳細級別要求或者系統復雜度的提高,使用要因分析法組合出詳盡的測試方案則成為了QA的一種折磨,每一個 QA遇到復雜的測試對象,都將成為酷刑下折翼的天使,欲哭無淚的在心中默默吶喊“坑爹啊”(因此要對要因法做一定程度的改良,如何改良,后文將詳述)。

            前文伏筆“要因分析法不是魚骨分析法”,魚骨分析法的另一個更加正式的書面稱呼是“根本原因分析法”(日本管理大師石川馨先生發展出來的,故又 名石川圖)。根本原因分析法同樣有著折磨常人的地方(題外話:為什么日本人使用的方法總是那么坑爹?),它要求分析者們集中精力尋求發生問題的任何一種可 能性(頭腦風暴),將這些可能性繪制在魚骨圖上,再尋求所有可能性的根源,其本質上不是一種用于設計測試方案的方法(僅僅用于追溯問題,例如發現bug后 追溯引起bug的根源)。關于根本原因分析法的討論,由于和本文的重點有偏離,因此不做進一步描述,題外話就此打住。

            歐美式頭腦風暴

            眾所周知,歐美企業的風格是強調人性和自由,對于測試來說,自然不可能采納日式那種條條框框的做法。測試方案設計的基本方法和準則,例如邊界值 分析、等價類劃分、因果圖等,被QA們牢牢的記在心中,功能測試方案設計時,根據需求分析或用戶手冊,眾人在一起集中進行頭腦風暴,此時包括RD也將參與 進來,對于測試合理或者不合理的地方提出建議。因此,方案設計的時候,更強調的是經驗和閱歷以及對需求的關注程度。測試方案設計是有偏重的,對于一些重要 的feature強烈關注,用例也將根據feature的重要性而詳略有別。

            頭腦風暴式的測試用例設計的輔助工具往往以思維導圖為主,還是以“我打算從南京去北京”為例,其中一種思維導圖設計如下:

          思維導圖的靈活性很高,因此設計出的導圖每次都會有所不同,跟隨著與會者偏重點的不同而產生不同的設計方案。

            好比歐洲的菜肴大多以整塊烹制為主,而中國人的菜肴則基本上都是切碎的。這是因為受限于傳統使用的餐具。而測試方案的設計方法也同樣受到西方和 東方文化差異的影響,例如Agile首先在歐美出現并迅速得到推廣和應用,而Agile絕對不會首先出現于日本。對于頭腦風暴式的測試方案設計,這頗有 Agile的風格,項目參與者進行充分的思想交流,QA們將每一個閃現于頭腦的想法都記錄在案,同時根據別的QA和RD的建議來不斷地修正或彌補方案,直 到完成設計。

            這種設計方法的好處是擁有很好的靈活性,且可以避免精力被耗費到旁枝末節上。用例可以是很多步驟組合起來的(表現為思維導圖的層次較多),通過 一個用例測到多個feature,這在進行具體的自動化測試代碼編寫時可以節省大量勞動力。由于交流足夠充分,某些不易被想到的測試用例也可以被挖掘出來 (好比繪制清晰的思維導圖)。然而,這種方法的缺點也是顯而易見的,某些測試用例有可能在頭腦風暴中被忽視或遺忘,且受限于人的思維的不嚴密性,未設計在 案的測試用例,往往也沒有人會關注到“為什么這些測試用例不用測”這個問題。

            歐美與日式的比較

            其實從上述的兩個篇章,我已經闡述了二者之間的差異。日式苦行僧般的要因分析法,幾乎可以遍歷窮舉所有可能的組合方式(除非因子有遺漏),設計 完畢后,到了具體測試實施階段,無論是手動測試還是自動化測試,對于QA來說,都是一個比拼耐力的考驗,測試用例數動輒過千,大量的測試用例之間甚至只有 細微的差別。QA將完全體驗不到創作的樂趣,轉而成為一名不折不扣的體力勞動者。一個測試對象的測試周期也被大大拉長,所需的人月數也很多。完成這些繁瑣 的工作之后,測試對象將趨于完美,細微的bug也將被找出并修正。此時不排除測試對象可能已經是一個落后的甚至被淘汰的產品了。當然,這對于用戶忠誠度極 高的日本人來說,這不算什么問題,他們不厭其煩的強調產品品質,但是對于這顆星球上的其他民族來說,大多寧可忍受一些小bug,也不愿使用一個過期的技術 落后的產品。

            對于歐美式的測試設計,顯然比較契合當前的飛速發展的計算機業,但產品中留下的bug數量往往也會比日式測試法多的多。這尤其表現在產品的一些局部的、次要的功能上,這些功能往往將成為bug集中營。

            兩者融合的思考

            歐美與日本,兩者采用的方法各有長處。一者的缺點往往恰是另一者的長處。那么該如何從兩者中取長補短,去粗取精以至互相融合呢?這也是我在工作中一直不斷思考的一個問題。

            我認為有一種可行的解決方案可以按照如下的做法進行:

            1、列出要因表,因子和狀態的列舉方式可以采用思維導圖進行

            2、根據deadline來劃分測試的詳略程度,制訂測試計劃

            3、頭腦風暴,將要因表的二維組合放在參與者的頭腦中進行

            4、在列舉測試用例的同時,對不測的用例也要追究一下不測的原因

            5、歸納測試用例之間的共性,對于差別較小的測試用例,要考慮如何整合到一起,對于可以串行的用例,要考慮是否可以合并為一個多步驟的用例

            通過以上5個步驟,我想既可以避免要因分析法的要因組合階段帶來的讓人抓狂的繁瑣和用例數量過多的缺陷,又可以避免頭腦風暴帶來的某些用例的考慮不周。

            是否還有其他更好的取長補短的方法呢?這個問題將依然縈繞在我的日常測試工作中,吾將上下求索,并期待您對本文的看法能夠給予我茅塞頓開的啟迪。


          posted @ 2011-10-10 09:35 順其自然EVO| 編輯 收藏

           第二章 單元測試的基本概念和核心技法

            第二章 單元測試的基本概念和核心技法

            2.1 良好的單元測試——定義

            我們已經了解了程序員需要單元測試,下面我們來給單元測試作一個完整的定義:

            ● 定義: 單元測試是一段自動執行的代碼,它調用被測類或被測方法,然后驗證關于被測類或被測方法邏輯行為的假設確實成立。單元測試幾乎總是用單元測試框架(unit testing framework)來寫就的,單元測試是易于寫就、執行快速、完全自動化、值得依賴、易于閱讀并易于維護的。

            這個定義有點長,但是它卻包含了大量重要信息:

            ● 單元測試的測試重點是被測類或被測方法的邏輯行為。所謂“邏輯行為”,指的是含有諸如判斷、循環、選擇、計算或其他決策過程的代碼。

            ● 單元測試框架是輔助程序員寫就單元測試的利器。

            ● 單元測試的代碼本身,同被測代碼一樣,也應該是值得依賴、易于閱讀并易于維護的。

            有了單元測試的定義,我們來看看有關單元測試的幾個基本概念,這些基本概念會在后面的章節中反復出現。

            ● 被測類(Class Under Test)和被測方法(Method Under Test):顧名思義,就是測試代碼所操練的類或方法。

            ● 測試類(Test Fixture)和測試方法(Test Method):負責操練被測類和被測方法。Test Method一般都是Test Fixture的成員函數。

            ● 測試運行器(Test Runner):負責自動執行測試類中的測試方法。Test Runner可以是命令行界面的,也可以是GUI的。

            2.2 進行單元測試的核心技術和核心手法

            2.2.1 核心技術

            前面已經講到,單元測試所針對的目標是“單個”類或“單個”方法(這里的“方法”指C++中的自由函數)。這表明我們在單元測試中要做的主要任務是創建出被測類的對象,并調用該對象的被測方法。但是我們都知道,一個類幾乎不可能完全不依賴于其他類。這種類之間的依賴會導致我們無法順利地將一個被測類納入單元測試覆蓋這下,因為單元測試需要的是對被測類這一個類的測試,而不是同時測試被測類和它的合作者類。

            因此,我們在把ClassUnderTest納入單元測試時,也就必須先把ClassUnderTest與CollaboratorClass之間的依賴“打破”,這個過程稱為“解依賴”(dependency-breaking)。解依賴就是進行單元測試的核心技術。解依賴的目標是希望能把不可控的CollaboratorClass替換成由我們控制的偽合作者類(FakeCollaboratorClass),并使被測類能方便地選擇是依賴于真實的合作者類還是偽合作者類。對于產品代碼,被測類依賴的是真實的合作者類,而在單元測試中,被測類依賴的是由我們控制的偽合作者。

            在單元測試代碼中使用可控的FakeCollaboratorClass,這給我們帶來了兩個便利:

            ● 我們可以通過FakeCollaboratorClass向ClassUnderTest返回任何我們指定的結果。

            ● 我們可以通過FakeCollaboratorClass來感知ClassUnderTest所做的動作。

            這實際上就是FakeCollaboratorClass的兩種表現形式:

            ● Stub:用于向ClassUnderTest返回我們指定的結果。

            ● Mock:用于感知ClassUnderTest的行為。

            我們明白了“解依賴”是單元測試的核心技術。那么具體怎樣實現解依賴呢?下面我們就來介紹4種相關的核心手法,其中前2種與CollaboratorClass有關,后2種與ClassUnderTest有關,這4種手法對于解決絕大多數的解依賴問題都適用。

           2.2.2 “接口提取”和“Virtual and Override”

            “接口提取”手法是對CollaboratorClass提取出一個抽象接口CollaboratorService,然后讓CollaboratorClass和FakeCollaboratorClass都去實現這個接口,而ClassUnderTest則由直接依賴CollaboratorClass轉向依賴于抽象接口CollaboratorService, 如下圖所示。

            實際上,“接口提取”手法是一種非常好的手法,它使得我們的代碼遵循“依賴抽象原則”,遵循這個原則的軟件具有較好的靈活性,這是具有可測試性的軟件也具有較好的設計的一個佐證。

            而“Virtual and Override”手法則是使CollaboratorClass中的被依賴方法成為virtual,然后讓FakeCollaboratorClass去公有繼承CollaboratorClass,并且override那些虛函數,從而替換掉 CollaboratorClass中的行為。這種手法如下圖所示。

            總體上講,我們推薦優先使用“接口提取”手法,因為這將使代碼遵循“依賴抽象原則”,從而使軟件更好地應對今后的變化。但是,“Virtual and Override”方法也是有其一席之地的,我們后面會看到例子。

            2.2.3 “參數注入”和“Extract and Override”

            在ClassUnderTest這邊,對CollaboratorClass的依賴的產生方式也可以劃分成兩類:

            依賴是通過方法參數傳入的,這種形式的依賴被稱為“參數注入”式依賴(parameter injection dependency)。參數注入式依賴是一種耦合度較低的依賴產生形式,因此對ClassUnderTest的影響不大,一般最多只需要把方法的簽名由直接依賴CollaboratorClass改成依賴接口CollaboratorService。

            依賴是在被測方法的方法體內部產生的,這種依賴被稱為“隱藏式”依賴(hidden dependency)。隱藏式依賴有多種表現形式:

            ● 直接創建CollaboratorClass對象作為局部變量或成員變量。

            ● 通過一個工廠方法來產生CollaboratorClass對象。

            ● 通過一個工廠類來產生CollaboratorClass對象。

            隱藏式依賴是一種耦合程度較高的依賴,因此是我們著重需要“打破”的依賴。一種方法是把隱藏式依賴轉變成參數注入式依賴,我們將在后面的小節中看到這種方法的應用。而另一種方法,則是使用“Extract and Override”手法,即:我們給ClassUnderTest引入一個virtual的工廠成員函數,來返回一個CollaboratorClass對象的引用,然后對ClassUnderTest派生出一個子類,在該子類中override這個工廠成員函數,讓它返回一個FakeCollaboratorClass對象的引用,如下圖所示。

            這里的TestingClassUnderTest被稱為“測試用子類”(Testing Subclass)。這時,在Test Fixture中被實例化的其實就是測試用子類,而不是被測類本身。

            以上我們研究了進行單元測試所需要的核心技術,以及4種最常用的核心手法,這些手法足以應付絕大多數的情況,但是,仍然有一些特殊情況需要我們特別注意,我們從下一節開始,以Q&A的形式,討論這些特殊情況。

           2.3 應付構造函數中的隱藏式依賴

            當ClassUnderTest中出現隱藏式依賴時,最常用的有兩種手法來打破這種依賴。我們分別來看一下。

            2.3.1 轉變成參數注入式依賴

            對于像C#和Java這樣的語言,由于它們支持在一個構造函數中去調用另一個構造函數,因此可以很方便地增加一個構造函數,把隱藏式依賴轉變成參數注入式依賴。下面的UML圖闡釋了這種手法。

            而對于C++,由于它沒有提供在構造函數中調用另一個構造函數的功能,因此通常的作法就是把公共的的初始化代碼放入一個init()私有方法中去,讓不同的構造函數去調用init()方法。

            2.3.2 使用“調包方法”

            還可以考慮給ClassUndertTest引入一個“調包方法”,使得測試類和測試方法可以很方便地將合作者類“調包”成偽合作者類。這里的“調包方法”本質上就是一個setter方法,但是為了表明這個特殊的setter方法只應該被測試類和測試方法調用,我們一般給調包方法命名為SupersedeCollaborator()。下圖就是一個演示。

            這里必須要提醒的是,在C++中使用這個手法時必須注意在“調包方法”中不能引起資源泄漏,也就是說,必須先釋放掉原有的合作者對象,再以偽合作者替代之。

            2.4 怎樣測試ClassUnderTest中的private方法?

            如果要測試一個類的private方法,答案的總體思路是:適當打破訪問權限。也就是說,我們可以把private方法聲明成protected方法,然后對ClassUnderTest進行派生,得到一個“測試用子類”,在該“測試用子類”中聲明一個public方法,該方法是ClassUnderTest中的protected方法的代理。這種手法可以用下圖來表示。


           2.4 應付“全局依賴”

            所謂“全局依賴”,是指被測類或被測方法所依賴的合作者是一個“全局單件”,包括C#/Java/C++中的“單件類”(Singleton)和C++中的全局變量和自由方法(實際上, Singleton可視為全局變量在面向對象語言中的變種)。我們下面來看看怎么應對這些情況。

            2.4.1 使用“封裝全局引用”手法來解除對全局變量和自由方法的依賴

            要打破對全局變量和自由方法的依賴,其實基本思想就是:把它們納入到一個類中,讓它們成為一個類的成員變量和成員方法。一旦把全局變量和自由函數封裝進了某個類,那么我們就可以繼續利用2.2.2節提到的兩種手法來引入偽合作者了。

            2.4.2 使用“靜態調包方法”來解除對單件類的依賴

            單件類往往具有3個特點:

            (1)單件類的構造函數通常被設為private。

            (2)單件類具有一個靜態成員變量,該成員變量持有該類的唯一一個實例。

            (3)單件類具有一個靜態方法,用來提供對單件實例的訪問,通常該方法名叫getInstance()。

            由于單件類被設計成強制性地在整個程序中只有一份,因此要偽造它比較困難。我們推薦使用“靜態調包方法”手法。這個手法的本質是適當打破單件類的單件性約束,把單件類的構造函數改為protected,使我們能夠從單件類派生出一個Fake子類,然后為單件類引入一個靜態調包函數SupersedeInstance(),以允許單件類中的靜態成員變量被“調包”成Fake子類對象。下圖表明了這一手法。

            同樣必須強調的是,在C++中的使用這個手法的時候,必須保證沒有資源泄漏。

            2.5 如果CollaboratorClass本身就處于繼承體系中,怎么辦?

            先設想一下CollaboratorClass本身存在基類的情況,如下圖所示。


          如果使用“Virtual and Override”手法來偽造合作者類,那么不存在任何問題,我們可以用下面的圖來表示。

            另一方面,如果想使用“接口提取”手法的話,那么一種比較好的策略是使用“外覆類”(Wrapper Class),如下圖所示。

            2.6 當CollaboratorClass是標準類庫的一員時,怎么辦?

            有些時候,我們的被測類所依賴的是特定操作系統(Windows, Unix, 或Mac)、特定標準規范(.NET,或J2EE)、特定函數庫或類庫(如POSIX API和Win32 API)及特定用戶界面(CUI或者GUI)所提供的功能時,這實際上是引入了對特定平臺的依賴性,而這往往都是在提示我們:應該加入一個更高層次的抽象(也即一個間接層,indirection),從而將這種對特定平臺的依賴隱藏到這個抽象之后。換句話說,我們應該引入一個接口,來使我們的代碼具有平臺無關性,如下圖所示。

            2.7 怎樣測試抽象接口?

            假設我們的系統中定義了一個抽象接口ServiceInterface,系統中有兩個類(分別是ServiceImpl1和ServiceImpl2)實現了這個接口。現在,我們希望為ServiceInteface抽象接口編寫一個通用的測試類,這個測試類不僅能測試當前已經實現該接口的類,而且可以不加修改地應用于將來實現ServiceInteface接口的類。應該怎么辦呢?下圖展示了一種可能的方案。

            上圖中,ServiceInterfaceTestFixture測試類中的測試方法都是基于ServiceInterface來進行測試的,不依賴于其具體實現類。這樣就保證了僅測試抽象接口所定義的行為。當將來系統引入ServiceInteface的新的實現類時,只需要從ServiceInterfaceTestFixture類再派生出一個新子類,并實現createServiceInstance()方法來創建相應的對象即可。

          posted @ 2011-10-09 22:08 順其自然EVO| 編輯 收藏

           第一章 為什么使用單元測試

           第一章 為什么使用單元測試

            1.1 程序員的工作——修改軟件

            修改既有代碼是程序員謀生的手段。但是為什么我們需要去修改軟件呢?修改軟件有以下4個主要起因:

            ● 修正bug

            ● 添加新特性(feature)

            ● 改善設計

            ● 優化資源使用

            這4項都與軟件的“行為”密切相關,見下表。


          軟件的既有行為
          軟件的新行為
          修正bug
          改變軟件的既有行為
          增加新行為
          添加新特性
          保持軟件的既有行為,完全不修改既有代碼
          改善設計
          保持軟件的既有行為,但軟件的可維護性得到提升
          優化資源使用
          保持軟件的既有行為,但軟件的性能得到提升

            通過這張表格我們看出:只有在修正bug時,我們才需要改變軟件的既有行為,而在其他情況下,我們都需要保持住軟件的既有行為。如果我們在改善設計,優化,或添加新特性時改變了軟件的既有行為,那我們實際上是給軟件引入了bug。

            可是程序員的工作就是修改軟件,所以我們有很多的“機會”給軟件引入bug。有什么辦法能讓我們的生活輕松一點,而不用因為修改代碼引入bug而擔驚受怕嗎?

            1.2 軟件夾鉗——測試

            我們已經看到:在大多數情況下,我們希望對軟件所做的改動不會改變系統的既有行為。即使是對于修正bug這種情況,我們也希望一旦bug被修正,那么修正后的正確行為能夠得到保持,而不會被再之后的代碼修改所改變。怎樣做到這一點呢?

             讓我們這樣想想:如果我們能在對代碼進行改動之前,用一種“軟件夾鉗”(software vise)來固定住軟件的既有行為,那么我們就可以放心大膽地去修改代碼了。那么,又是什么可以來充當“軟件夾鉗”呢?答案是:測試。我們可以這樣想一 下:當一段代碼被一組良好的測試所覆蓋時,我們就可以放手去修改這段代碼,并在修改完成之后立即運行這組測試,來驗證我們的修改并沒有改變既有行為而引入 bug。如果確實改變了既有行為,那么測試就會明確無誤地發出警報。由此可見,測試就是程序員所需要的“軟件夾鉗”。

            1.3 單元測試與集成測試之爭

            我們已經知道了“測試”就是程序員所需要的“軟件夾鉗”。但是測試分為單元測試和集成測試,程序員需要哪種測試呢?讓我們來分析一下程序員需要什么樣的測試,這樣或許我們就能知道程序員應該更偏向于哪種測試了。

            ● 程序員需要的測試應該是能幫助程序員定位錯誤的,這樣程序員才會真正地從測試中得到“實惠”。

            ● 程序員需要的測試應該是很容易執行的,最好是只需點擊一個按鈕或鍵入一條命令,這些測試就能運行,而無需費時費力地去搭建測試環境及準備測試數據或儀器。

            ● 程序員需要的測試應該是運行速度很快的,最好能在幾分鐘內完成,這樣程序員才能快速地得到反饋,采取下一步動作。

            ● 程序員需要的測試應該是易于寫就的,而不愿意對代碼基大動干戈,這樣程序員才會愿意去寫這些測試。

            ● 程序員需要的測試應該是自動化的,可重復的。這樣程序員才會愿意重復多次地去運行這種測試。

            比對程序員的需求,我們可以發現集成測試往往不能滿足程序員的這些需求:

            ● 集成測試由于涉及多個模塊,因此往往不能提供準確的錯誤定位信息。

            ● 集成測試的執行時間一般較長(小時級),這不能給程序員帶來快速反饋。

            ● 集成測試可以自動化執行,但前提是把測試環境和測試數據等事先準備好。

            ● 集成測試由于不太容易寫就,通常不是由程序員寫就,而由專門的測試人員寫就。

            相反,單元測試,尤其是良好的單元測試,恰恰正是程序員所需要的那種測試:

            單元測試針對單個類或單個方法,能很有成效地幫助程序員準確定位問題所在。

            單元測試應該是執行時間很短的,全部執行也只需5到10分鐘,程序員正好可以去喝喝咖啡。

            單元測試是一種“虛擬”測試,重在測試代碼邏輯,因此一般不需要真實測試環境和測試數據的支持。

            單元測試是很容易寫就的,尤其是有單元測試框架的幫助時。

            由此可見,對于程序員而言,需要的是單元測試。程序員使用單元測試來充當軟件夾鉗,并在修改代碼時獲得快速反饋,從而更有信心地投入到修改軟件的工作中。

            1.4 進行單元測試的其他好處

            我們已經知道了單元測試帶來的一個好處:它可以充當程序員的“軟件夾鉗”,在程序員修改軟件的過程中給予程序員快速的反饋,幫助程序員定位問題,避免引入bug。單元測試就只有這一個好處嗎?不是的。下面我們就來看看引入單元測試帶來的其他好處。

            1.4.1 單元測試是代碼的“活文檔”

            讓文檔及時反映軟件設計和代碼的最新情況,這是一個頗有挑戰性的問題。一種較好的思路是:使用“內部”文檔,即把文檔同代碼“拴”在一起。這樣當代碼發生改變的時候,文檔也能相應更新。注釋就是一種內部文檔,良好的注釋應該反映代碼的最新狀況。

            類比來看,單元測試同樣也是內部文檔,因為單元測試本質上也是描述了被測類或被測方法的行為。對軟件行為不了解的程序員,可以通過閱讀單元測試 代碼來理解軟件的行為。同注釋相比,單元測試還具有一個更好的特性:它是一種“可執行”文檔。如果單元測試在被執行時無法通過,那么說明要么單元測試沒有 反映當前代碼的真實狀況,要么說明代碼中有bug。無論哪種情況,程序員都需要修改某一方,以保持兩者的一致。

            1.4.2 具有可測試性的軟件具有更高的質量

            近年來流行的極限編程方法論推崇“測試驅動開發”。我們認為,“測試驅動開發”并不一定要求必須先有測試后有代碼,而關鍵在于要求在設計軟件和 實現編碼時,一定要預先把軟件的可測試性考慮周全。這種可測試性的重要體現就是能夠方便地將單個類或方法納入單元測試之中。具有可測試性的軟件的質量往往 高于不具有可測試性的軟件,為什么這樣說呢?

            ● 一個類能夠被方便地納入單元測試,往往說明這個類職責單一,也就是說它滿足“單一職責原則”。

            ● 一個類能夠被方便地納入單元測試,往往說明它與其他類之間的耦合程度較低,相互依賴性較小,而且很可能滿足“依賴抽象原則”和“開放-封閉原則”。

            因此, 具有可測試性的軟件,也更有可能是滿足良好設計原則的軟件,所以往往質量更高。

          posted @ 2011-10-09 18:14 順其自然EVO| 編輯 收藏

          從單元測試到基于每日構造的自動測試

          1、單元測試

            XXXX作為一個新項目,和其他所有項目一樣,在開發工作進行之初就在考慮如何保證代碼開發的質量。答案很容易找到:充分的單元測試。但是以前真正做得好得項目卻不多。

            經過分析,總結了一下做好單元測試工作的四個要素:

            ――思想上的重視

            ――計劃上保證

            ――測試手段保證

            ――測試效果的可驗證

            1.1 思想上重視

            從以往的開發過程總結了一些教訓:

            ――開發人員模塊在交付聯調前,測試不充分,導致聯調周期較長

            ――代碼進入維護期后,修改代碼往往引起不可預期的錯誤。導致開發人員比較害怕在相對穩定的代碼上進行修改。

            由于有這些教訓,所以在編碼之前,項目從領導到員工都很重視單元測試工作。

            1.2 計劃上保證

            計劃制定經過了XXXX的分解流程,XXXX分解小組成員討論時充分意識到了單元測試工作的必要性,也意識到了為之要付出的代價。最終確定了單元測試和代碼開發的比重為2:1左右。以操作維護的配置模塊為例,最終制定的計劃如下:

            從計劃中可以看出,花在單元測試上的時間和代碼開發的時間的比重甚至超過了2:1。

            附:表方法測試代碼和被測代碼的行數統計數據(該部分測試覆蓋率已達95%以上)

            從數據看來,我們當初的估計是對的。測試代碼行數和被測代碼行數的比值大致是2:1

            1.3 測試手段保證

            1.3.1 測試框架

            對于一個系統工程來說,一個好的框架是至關重要的。一個好的框架應該有如下一些特點:

            ――結構清晰。不同的粒度層次在框架中一目了然

            ――可擴展性良好。

            我們選擇單元測試工具就是為了滿足能基于該工具搭建一個好的單元測試框架,另外還有以下幾個方面的考慮:

            ――整個開發組負責三個模塊:數據庫,操作維護,傳輸。每個模塊由不同的開發人員負責。從測試代碼的可維護性考慮,需要統一各人編寫測試代碼的框架以及風格

            ――前臺代碼是由C語言編寫的

            ――單元測試應該是可回歸的,自動化的

            最終我們選擇了Cunit,因為Cunit完全符合我們的要求。

          Cunit是一種針對于C語言代碼的單元測試框架,具有以下優點:

            –提供很多實用的接口函數(比如:各種斷言、信息匯總、打印等)

            –簡單、安全、方便

            –可添加任意多個測試單元

            –逐步添加,匯總成套,全面回歸測試

            –完全免費

            測試框架選定以后,在組內進行了相應的培訓,使得每個人的認識達到相同的水平,盡可能保證以后測試風格的一致。

            1.3.2 測試方案和測試規程

            單元測試是一個系統的工作,在進行之前需要一個總體的規劃。這個工作在單元測試方案中得到體現;測試規程是對測試方案的細化,是單元測試的指導。測試規程可以在notes的測試管理平臺中錄入。

            1.3.3 自動化測試的考慮

            一個單元測試是由許多測試用例構成的,要實現可回歸,自動化的測試,每個測試用例都應該可以按照一定的順序連續的執行。要達到這個目標,就要求對整個單元測試做一個很好的規劃。以數據庫模塊為例,我們做了如下的規劃:

            ● 數據環境的建立

            數據庫的測試依賴于一套數據表。單元測試一開始就需要在表中插入數據,以建立后續測試用例依賴的數據環境

            ● 測試粒度合理的劃分

            我們把被測對象分為表方法、查詢接口和修改接口。

            注:測試用例套(TestSuite)是Cunit的一個概念,用于封裝測試用例套或者測試用例(TestCase)

            ● 在某種粒度上面保證數據環境的松耦合

            所有的測試用例基于數據環境編寫,數據環境對于數據庫的單元測試是及其重要的。每個測試用例從前一個用例繼承數據環 境,又將本測試用例修改后的數據環境移交給下一個測試用例。從這個過程可以看出,數據環境在測試用例間是緊耦合的。如果測試用例一多,數據環境就會變得難 以控制,用例的編寫將變得非常麻煩。尤其是多人分工合作的情況下,簡直變成了不可能的任務。

            幸好我們有測試套!

            以表方法的測試套為例,在第二級粒度上,一個套就是一張表所有表方法測試用例的集合。這個套包含的測試用例大致在 4、5個左右。我們的策略是:二級粒度測試套內部的測試用例緊耦合數據環境,而二級粒度套之間的數據環境為松耦合。這通過在每個二級粒度套內加入一個數據 環境恢復用例來實現。

            這樣一來,我們可以按照二級粒度的測試套來分工編寫測試代碼。

          ● 樁函數的考慮

            單元測試是不依賴其他模塊的測試。但是實際代碼中存在對其他模塊函數的調用。為了消除這種依賴關系,就需要編寫樁函數來替代對外部模塊函數的調用。

            為了清晰起見,我們的樁函數集中在一個文件中。

            樁函數只是一個實現,至于原形定義,還是要引用其他模塊的頭文件,這樣可以跟蹤其他模塊函數接口最新的改動。

            ● 單元測試工程的規劃

            一個清晰合理的單元測試工程規劃是必要的,這樣有利于對象的查找和維護。

            以DBS模塊的單元測試為例,我們的工程結構如下圖所示。

            1.3.4 測試效果的可驗證

            如何來量化單元測試的效果?

            覆蓋率是一個最直觀的指標。我們采用了Rational公司的Pure Coverage工具來獲取覆蓋率。這也是公司推薦的一個簡單易上手的工具。我們要求測試覆蓋率達到90%以上。

            2、自動測試

            2.1 每日構造

            每日構造是公司推行的一個最佳實踐。它有一下一些功能:

            ● 開發人員及時把最新代碼放入代碼庫,及時check out和check in,避免積累大量代碼

            ● 及時進行模塊間的整合,及時發現問題

            ● 對部分功能進行測試,無需等待

            ● 使用測試用例工具,對功能進行完整和重復的檢驗

            ● 記錄所有程序問題

            ● 實現解決Bug的自動流程

            ● 提高正式版本提交的質量和速度

            ● XXXX在軟件上開始推行每日構造。

            2.2 冒煙測試

            如果在每日構造的同時進行“冒煙測試”,能最早發現版本的問題。“冒煙測試”是微軟提出的名詞。其

            對象是每一個新編譯的需要正式測試的軟件版本,目的是確認軟件基本功能正常,可以進行后續的正式測試工作。“冒煙測試“的執行者是版本編譯人員。

            ZXWR-RNS網管項目已有用Robot在網管產品進行冒煙測試的實踐。但是對于前臺軟件,公司內部尚未有這方面的嘗試。

            2.3 自動測試

            基于前期模塊的單元測試工作,一個自然的想法就是在每日構造的框架上運行模塊的單元測試代碼,實現前臺軟件的每日自動化測試。這是比“冒煙測試”更全面,更徹底的一個測試。

            2.3.1 單板軟件

            模塊1

            模塊2

            模塊n

            模擬測試工具

            XXXX軟件的架構


            2.3.2 自動測試的規劃

            2.3.2.1 自動測試的級別

            從軟件的構成來考慮,分三級構造測試工程:

            ● 模塊單元級:基本的軟件單元

            ● 板級:由多模塊組成的單板軟件

            ● 系統集成級:由模擬測試軟件和單板軟件組成

            這三個級別的測試是互相補充的關系。每日構造進行三個級別的測試,這樣就比較完整了。

            2.3.2.2 測試代碼的管理

            要實現每日構造并進行自動測試,必須將測試代碼也提升到被測代碼同等的地位,納入CC的管理。在CC上的目錄結構如下所示:

            BoardSWS
            -BoardTest \\板級測試工程目錄,包含測試用例代碼以及板級測試工程
            -SystemTest \\系統集成級工程目錄,不含測試用例,僅含工程
            -SCMM
            -UnitTest \\模塊單元級測試目錄,包含該級測試用例以及測試工程
            -SCMM源碼
            -Cunit \\模塊單元級測試用Cunit文件
            -其他模塊
            -Cunit \\板級測試用Cunit文件

            SimuRNC
            -SystemTest \\系統集成級測試工程目錄,包含測試工程和測試用例
            -SimuRNC源碼
            -Cunit

            基于這樣的目錄結構,發布代碼和測試代碼在CC中納入同一個VOB管理比較方便。這樣一來,測試代碼和發布代碼執行相同的CC-CQ關聯策略。也就是說,修改測試代碼也需要和CQ關聯。

            2.3.3 自動測試的執行

            自動測試由版本室完成。自動測試執行分為四個步驟:

            ● 同步CC的文件到本地

            ● 編譯各測試工程(VC環境),輸出編譯結果文件

            ● 執行編譯結果,輸出測試執行結果文件

            ● 將編譯結果導入

            notes

            上述步驟都是通過編寫一個BAT文件掛在WINDOWS的“任務計劃”中每日自動完成。

            附:
            BAT文件(DBS模塊)
            編譯結果 (DBS模塊)
            測試執行結果(DBS模塊)

            2.3.4 自動測試的目標

            依附于每日構造機制,自動依序運行三個級別的自動測試,測試產生的結果輸出到文本文件。然后通過自動分析腳本提取該文件中沒有通過的用例信息,發送郵件通知相關責任人進行分析處理。如此做到“日事日畢”,將故障扼殺在萌芽狀態,保證代碼質量的穩定。


          posted @ 2011-10-09 17:29 順其自然EVO| 編輯 收藏

          單元測試的效益

          單元測試的效益

            單元測試是針對代碼單元,特別是算法密集的代碼單元的獨立測試,可以完整覆蓋代碼單元的功能邏輯,保證代碼質量、降低成本、提高生產率、縮短開發周期、贏得市場先機、提升產品競爭力。

            單元測試分為靜態和動態,靜態方法只能發現小部分錯誤,例如,加法函數

            int add(int a, int b){return a-b;};

             加號寫成了減號,這種最簡單代碼中的最簡單錯誤,任何靜態工具都無法發現,而動態方法只需輸入兩個1,自動判斷輸出是否等于2,馬上就能發現錯誤。靜態 方法能發現的錯誤,如除零錯、數組越界、條件語句中==寫成=,都會表現為異常或功能錯誤,動態方法當然也能發現,因此,動態方法是單元測試的根本方法。

            無處不在的80-20規則,在軟件開發中 同樣存在,例如,80%的錯誤存在于20%的代碼中,80%的項目時間消耗在20%的代碼上,當然這只是粗略的估計。“20%代碼”就是邏輯復雜的代碼, 也就是算法密集的代碼。一個算法密集的函數,要對輸入仔細分類,一個判定就是一次分類,嵌套的判定更使分類次數翻番,遺漏一個分類,或一個分類處理不正 確,就會造成錯誤。只有完整覆蓋代碼單元的所有輸入等價類,才能保證發現這些錯誤,這在調試和系統測試中是難于做到的。算法密集的代碼包含了項目中的大多數錯誤,即使只對這部分代碼實施單元測試,也能產生理想的效益。

            除了保證代碼質量,單元測試還具有排錯成本最低、易于自動回歸、縮短后續測試周期、提高編程效率等顯著效益。

          posted @ 2011-10-09 16:32 順其自然EVO| 編輯 收藏

          在Eclipse中使用JUnit

          在Eclipse中使用JUnit

          文章出處:CSDN 作者:rosen 發布時間:2005-10-24


          這篇文章將向你介紹Junit,一個用來在項目中進行測試和調試的工具。在介紹完TDD(以測試驅動開發)理論后,將進一步講解怎樣在流行的Eclipse中建立你自己的JUnit測試。向你展示如何測試Hello World這樣簡單的程序。

             

              許 多書上都討論了自動測試,但是只有很少的著作注意到這么一個問題,那就是怎樣把這些測試組織起來。隨著測試的增加,放置和調用這些測試卻變得更加麻煩。這 將成為一個重要問題,以至于出現了TDD,極限編程(XP)使TDD得以普及。另外,你可以這樣理解TDD:通過測試來開發。

             

              TDD的主要規范:

             

              在編寫程序代碼之前,與之對應的自動測試必須被寫好。甚至程序代碼并不存在,那也要看見一個失敗的測試結果。

              在測試通過后,副本代碼必須被丟棄。

             

              有一個具體步驟(可能指的是《Extreme Programming》)可以被任何一個程序員來參考,而不需要特殊的其他方法。在我們開始寫測試之前,這些步驟(章節)應該被首先閱讀——怎樣組織自動測試。

             

              講解一下不同種類的測試:

             

              單元測試:檢測模塊(也就是類)的正確性。如果對象需要訪問外部的數據資源,例如數據庫,就需要模擬一個mock objects,但在實際中真實數據與測試環境是不同的。

              客戶測試:這是功能性、系統、和驗收測試。用來測試整體的系統特性。在XP中,這些測試由用戶編寫。

              綜合測試:介 于用戶測試和單元測試之間的橋梁。綜合測試幫助測試應用程序的交互性。一般情況下,mock objects不被用于綜合測試,它會增加測試時間。同樣,綜合測試經常依賴特殊的測試環境,例如數據庫送來的測試數據。綜合測試也需要用到外部類庫。例 如為J2EE應用程序進行綜合測試的類庫Cactus。解釋這些測試超出了本文的范圍,需要更加詳細的信息請參考http://jakarta.apache.org/cactus/

              開發人員測試:這是用來讓開發人員檢驗自己代碼或新函數的。對于每一個開發人員,只要有可能,就需要有更多的測試來檢驗代碼。組織這些測試和組織程序代碼一樣重要。

             

              在以下章節,只要提到“測試”,那就指的是開發人員測試。

              

              我們幾乎準備好開始建立測試了,先應該為我們的測試選擇名字。你也許會說,“這不是問題:把‘Test’這個字放在類名前面,就好了!”不會這么快!讓我來說一下這個步驟存在的問題:

             

              在TDD中,被測試的類或者方法還不存在。

              一個測試能夠覆蓋多個方法,甚至多個類,這是可能的。

             

              以上只是一些普遍問題;還存在更多的問題。

             

              讓我來提一個建議,在測試命名時:測試類的名字應該讓人一眼就知道這是一個測試類,且能說明它要測試什么,注意是否和其他類重名。按照以上建議做,就很簡單了,也不用擔心名字太長或難聽。

             

              即 將在Eclipse中用JUnit工具創建我們第一個測試了。假設你已經下載了一個最新的Eclipse版本。如果還沒有,你應該去官方站點 http://www.eclipse.org下載。還需要JUnit,也可以從http://www.junit.org/下載。

             

              運行Eclipse。新建一個workplace項目,點擊文件->新建->項目,選擇Java項目,點擊下一步。起一個項目名稱,例如ProjectWithJUnit。點擊完成。這樣就完成新項目的建立了。再來配置一下Eclipse,在構建路徑中添加JUnit類庫。在工具條上點擊項目->屬性,選擇Java構建路徑,選擇添加外部JAR,瀏覽Junit被存儲的目錄,選擇junit.jar,點擊打開。你將會看見JUnit出現在庫的列表中。點擊確定,讓Eclipse重建路徑。

             

              現在開發我們的“Hello World”例子。按照TDD的規則,應該在代碼建立以前先把測試寫好。為了能夠在某出開始,我們假設未來的類名是HelloWorld,并且有一個方法Say(),這個方法返回String的值(例如“Hello World!”)。

             

              建立測試,在ProjectWithJUnit的標題上面點擊右鍵,選擇新建->其他,展開“Java”選項,選擇JUnit。在右邊的欄目對話框中選擇測試案例,然后下一步。參考圖1。

           

                 

                              圖1. 在Eclipse中建立JUnit測試

             

              在測試類這一欄中,寫上將要被測試的類名HelloWorld。選擇一個測試案例的名字,例如TestThatWeGetHelloWorldPrompt(是的,看上去很長,但是很清楚它的行為。)點擊完成

             

              TestThatWeGetHelloWorldPrompt的代碼如下:

           

              import junit.framework.TestCase;

           

              public class TestThatWeGetHelloWorldPrompt

              extends TestCase {

                  public TestThatWeGetHelloWorldPrompt(

                      String name) {

                      super(name);

                  }

                  public void testSay() {

                      HelloWorld hi = new HelloWorld();

                      assertEquals("Hello World!", hi.say());

                  }

                  public static void main(String[] args) {

                      junit.textui.TestRunner.run(

                          TestThatWeGetHelloWorldPrompt.class);

                  }

              }

           

              代碼并不復雜;只是有點與眾不同。然而,讓我們考察一下細節。我們繼承了JUnit的TestCase類,它在JUnit的javadocs定義為“運行眾多測試的夾具。”JUnit也有TestSuite類,它是一組測試案例的集合,但在本文中不做討論。

             

              建立測試案例的步驟如下:

             

              1、建立一個junit.framework.TestCase的實例。

              2、定義一些以“test”開頭的無返回方法(例如testWasTransactionSuccessful(),testShow(),等等)。

             

              TestThatWeGetHelloWorldPrompt.java包含這些:TestCase的子類和一個叫做testSay()的方法。這個方法調用了assertEquals()函數,它用來比較我們預期的值和由say()返回的值。

             

              main() 方法用來運行測試和顯示輸出的。JUnit的TestRunner處理測試,提供基于圖像和文本的輸出表現形式。我們使用基于文本的版本,因為 Eclipse支持它,且也適合我們。當開始運行后,基于文本的版本測試會以文本形式輸出,Eclipse會把這些輸出自動變成圖像界面的輸出。

             

              按照TDD規范,首次運行測試,應該故意讓它失敗。點擊運行->運行為->Junit測試(記住TestThatWeGetHelloWorldPrompt.java應該被突出的顯示在包資源管理器中)。在左邊窗口,應該看見JUnit窗口而不是包資源管理器,它顯示一個紅條,一次失敗的測試,具體的失敗原因參看圖2。如果沒有自動顯示這些內容,點擊JUnit標簽(在底部的左邊)。

           

                    

                              圖2. JUnit中失敗的測試

             

              很好!的卻失敗了。現在我們來建立被測試代碼:在包資源管理器窗口的ProjectWithJUnit標題上右擊,選擇新建->。選擇類名,我們已經假設了它叫HelloWorld,然后直接點擊完成。為HelloWorld.java填入下列代碼:

           

                  public class HelloWorld {

                      public String say() {

                          return("Hello World!");

                      }

                  }

                 

              這段代碼很簡單,甚至不需要注解,我們再來看看結果。按照上面描述過的方式,在JUnit的窗口中顯示了一個綠條,參看圖3。綠條證明測試成功。

           

                    

                               圖3. JUnit中成功的測試

                                        

              現在,我們想再讓測試失敗一次,但原因不同。這有助于展示JUnit測試中不同的報錯信息。修改assertEquals()代碼,把“Hello World!”變成“Hello Me!”。當再次運行JUnit時,結果變成了紅條,在JUnit窗口的底部輸出了失敗原因,參看圖4。

           

                     

                              圖4. JUnit中的ComparisonError

                                       

              最 后,我想說一下關于測試是開發過程中的必要部分的話題。測試代碼一直是開發中的重要部分。經過近幾年的發展,已得到了很大的提高,這要歸功于強大的理論研 究(比如“expectations-based development”等等),和快速發展的測試工具包,還有測試過程的改進。如果你對這篇文章感興趣,那請你花一些時間來正式的學習一下測試理論吧, 這對你的工作很有用。

          posted @ 2011-10-09 15:44 順其自然EVO| 編輯 收藏

          僅列出標題
          共394頁: First 上一頁 386 387 388 389 390 391 392 393 394 下一頁 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 静宁县| 彰化县| 德庆县| 云阳县| 平泉县| 山丹县| 高淳县| 余庆县| 永福县| 榆社县| 元谋县| 黄浦区| 疏勒县| 广宗县| 南城县| 神农架林区| 尤溪县| 巴塘县| 达日县| 阿巴嘎旗| 新密市| 黑水县| 陆良县| 长子县| 沭阳县| 泰安市| 灵宝市| 梅州市| 通许县| 云霄县| 南陵县| 晋城| 岳普湖县| 山西省| 海口市| 丰镇市| 凤翔县| 青阳县| 阳泉市| 谷城县| 华阴市|