• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 21,  comments - 20,  trackbacks - 0
             

            標準庫<cstdlib>(被包含于<iostream>中)提供兩個幫助生成偽隨機數的函數:

            函數一:int rand(void);
            從srand (seed)中指定的seed開始,返回一個[seed, RAND_MAX(0x7fff))間的隨機整數。

            函數二:void srand(unsigned seed);
            參數seed是rand()的種子,用來初始化rand()的起始值。

            可以認為rand()在每次被調用的時候,它會查看:
            1) 如果用戶在此之前調用過srand(seed),給seed指定了一個值,那么它會自動調用
            srand(seed)一次來初始化它的起始值。

            2) 如果用戶在此之前沒有調用過srand(seed),它會自動調用srand(1)一次。

            根據上面的第一點我們可以得出:
            1) 如果希望rand()在每次程序運行時產生的值都不一樣,必須給srand(seed)中的seed一個變值,這個變值必須在每次程序運行時都不一樣(比如到目前為止流逝的時間)。
            2) 否則,如果給seed指定的是一個定值,那么每次程序運行時rand()產生的值都會一樣,雖然這個值會是[seed, RAND_MAX(0x7fff))之間的一個隨機取得的值。
            3) 如果在調用rand()之前沒有調用過srand(seed),效果將和調用了srand(1)再調用rand()一樣(1也是一個定值)。

            舉幾個例子,假設我們要取得0~6之間的隨機整數(不含6本身):

            例一,不指定seed:
            for(int i=0;i<10;i++){
            ran_num=rand() % 6;
            cout<<ran_num<<" ";
            }
            每次運行都將輸出:5 5 4 4 5 4 0 0 4 2

            例二,指定seed為定值1:
            srand(1);
            for(int i=0;i<10;i++){
            ran_num=rand() % 6;
            cout<<ran_num<<" ";
            }
            每次運行都將輸出:5 5 4 4 5 4 0 0 4 2
            跟例子一的結果完全一樣。

            例三,指定seed為定值6:
            srand(6);
            for(int i=0;i<10;i++){
            ran_num=rand() % 6;
            cout<<ran_num<<" ";

            }
            每次運行都將輸出:4 1 5 1 4 3 4 4 2 2
            隨機值也是在[0,6)之間,隨得的值跟srand(1)不同,但是每次運行的結果都相同。

            例四,指定seed為當前系統流逝了的時間(單位為秒):time_t time(0):
            #include <ctime>
            //…
            srand((unsigned)time(0));
            for(int i=0;i<10;i++){
            ran_num=rand() % 6;
            cout<<ran_num<<" ";

            }
            第一次運行時輸出:0 1 5 4 5 0 2 3 4 2
            第二次:3 2 3 0 3 5 5 2 2 3
            總之,每次運行結果將不一樣,因為每次啟動程序的時刻都不同(間隔須大于1秒?見下)。

            關于time_t time(0):

            time_t被定義為長整型,它返回從1970年1月1日零時零分零秒到目前為止所經過的時間,單位為秒。比如假設輸出:
            cout<<time(0);
            值約為1169174701,約等于37(年)乘365(天)乘24(小時)乘3600(秒)(月日沒算)。

            另外,關于ran_num = rand() % 6,

            將rand()的返回值與6求模是必須的,這樣才能確保目的隨機數落在[0,6)之間,否則rand()的返回值本身可能是很巨大的。
            一個通用的公式是:
            要取得[a,b)之間的隨機整數,使用(rand() % (b-a))+ a (結果值將含a不含b)。
            在a為0的情況下,簡寫為rand() % b。

            最后,關于偽隨機浮點數:

            用rand() / double(RAND_MAX)可以取得0~1之間的浮點數(注意,不同于整型時候的公式,是除以,不是求模),舉例:
            double ran_numf=0.0;
            srand((unsigned)time(0));
            for(int i=0;i<10;i++){
            ran_numf = rand() / (double)(RAND_MAX);
            cout<<ran_numf<<" ";
            }
            運行結果為:0.716636,0.457725,…等10個0~1之間的浮點數,每次結果都不同。

            如果想取更大范圍的隨機浮點數,比如1~10,可以將
            rand() /(double)(RAND_MAX) 改為 rand() /(double)(RAND_MAX/10)
            運行結果為:7.19362,6.45775,…等10個1~10之間的浮點數,每次結果都不同。
            至于100,1000的情況,如此類推。

            以上不是偽隨機浮點數最好的實現方法,不過可以將就著用用…

            本文轉自赤龍發表的同名文

            posted @ 2008-08-16 11:53 Niino 閱讀(51650) | 評論 (6)編輯 收藏

            定義完一個class一定要加;啊~~

            posted @ 2008-08-06 14:17 Niino 閱讀(187) | 評論 (0)編輯 收藏
            struct stu
            {
            char a;
            char b;
            double c;
            }

            問sizeof(stu)=?
            答案16

            111->1+1+1
            114->(1+1)+(1+1)+4
            118->(1+3)+(1+3)+8
            141->(1+3)+4+(1+3)
            144->(1+3)+4+4
            148->(1+3)+4+8
            181->(1+7)+8+(1+7)
            188->(1+7)+8+8
            411->4+(1+1)+(1+1)
            414->4+(1+3)+4
            418->4+(1+3)+8
            441->4+4+(1+3)
            444->4+4+4
            448->4+4+8
            481->(4+4)+8+(1+7)
            484->(4+4)+8+(4+4)
            488->(4+4)+8+8
            811->8+(1+3)+(1+3)
            814->8+(1+3)+4
            818->8+(1+7)+8
            841->8+4+(1+3)
            844->8+4+4
            848->8+(4+4)+8
            881->8+8+(1+7)
            884->8+8+(4+4)
            888->8+8+8

            不同的編譯器下會產生不同的情況,以上在VS2005和DVE-CPP上已驗證
            有空補空,沒空對齊



            posted @ 2008-07-23 18:59 Niino 閱讀(268) | 評論 (0)編輯 收藏
            #include "stdafx.h"
            #include 
            <iostream>
            #include 
            <fstream>
            #include 
            <iterator>
            #include 
            <algorithm>
            #include 
            <vector>
            #include 
            <string>

            using namespace std;

            int main()
            {
                ifstream in_file( 
            "input_file.txt" );
                ofstream out_file( 
            "output_file.txt" );
                
                
            if ( ! in_file || ! out_file )
                
            {
                     cerr
            <<"!!unable to open the necessary files.\n";
                     
            return -1;
                }

                
                istream_iterator
            < string > is( in_file );
                istream_iterator
            < string > eof;
                
                vector 
            < string > text;
                copy( 
            is, eof, back_inserter( text ));
                
                sort( text.begin(), text.end() );
                
                ostream_iterator
            < string > os( out_file," " );
                copy( text.begin(), text.end(), os );
            }
            代碼如上,是<<Essential C++>>中的一段
            input_file的內容為"7 956 1 5 147 3 78 24 87 62 45 12 77 86 64 52 58 74"
            執行后
            output_file中內容為"1 12 147 24 3 45 5 52 58 62 64 7 74 77 78 86 87 956"

            - -
            sort()對字符串排序...shit...只認首字符
            posted @ 2008-07-19 12:36 Niino 閱讀(177) | 評論 (0)編輯 收藏
            調查的主題是在各位學習和使用C++或其他編程語言時,通常每天在電腦前花的時間:
            1.兩個小時以下
            2.兩到四個小時
            3.四到八個小時
            4.八小時以上

            歡迎大家發言
            posted @ 2008-07-19 11:03 Niino 閱讀(897) | 評論 (6)編輯 收藏
            角色扮演游戲引擎的設計原理--轉自MOVE2008 角色扮演游戲引擎的設計原理   
                  角色扮演游戲(RPG)是深受廣大游戲迷們喜愛的一種游戲, 它以獨特的互動性和故事性吸引了無數的玩家。它向人們提供了超出現實生活的廣闊的虛擬世界,使人們能夠嘗試扮演不同的角色,去經歷和體驗各種不同的人生旅程或奇幻經歷。這些體驗都是在現實生活中無法實現的。在玩過許多游戲后,許多玩家都不再僅僅滿足于一個游戲玩家的身份,而會思考游戲是如何制作的,并且打算制作一個自己的游戲,網上的各種游戲制作小組更是如雨后春筍般涌現。下面我就給大家介紹一下角色扮演游戲引擎的原理與制作,希望能對游戲制作愛好者有所幫助。 一 游戲引擎的原理   說到引擎,游戲迷們都很熟悉。游戲引擎是一個為運行某一類游戲的機器設計的能夠被機器識別的代碼(指令)集合。它象一個發動機,控制著游戲的運行。一個游戲作品可以分為游戲引擎和游戲資源兩大部分。游戲資源包括圖象,聲音,動畫等部分,列一個公式就是:游戲=引擎(程序代碼)+資源(圖象,聲音,動畫等)。游戲引擎則是按游戲設計的要求順序的調用這些資源。 二 角色扮演游戲的制作   一個完整的角色扮演游戲的制作從大的分工來說可以分為:策劃,程序設計,美工,音樂制作以及項目管理,后期的測試等。   策劃主要任務是設計游戲的劇情,類型以及模式等,并分析游戲的復雜性有多大,內容有多少,策劃的進度要多快等因素。   程序設計的任務是用某種編程語言來完成游戲的設計,并與策劃配合,達到預期的目的。   美工主要是根據游戲的時代背景與主題設計游戲的場景及各種角色的圖象。   音樂制作是根據游戲的劇情和背景制作游戲的音樂與音效。   項目管理主要是控制游戲制作的進程,充分利用現有的資源(人員,資金,設備等),以達到用盡量少的資金實現最大的收益。   后期的測試也是非常重要的一個環節,對于一個幾十人花費幾個月甚至是幾年時間制作的游戲,測試往往能找到許多問題,只有改進程序才能確保游戲的安全發行。   由于文章主要是講解游戲程序的制作的,所以策劃,美工,音樂制作等方面請讀者參考其它文章,下面我就講講游戲程序的設計。 (一) 開發工具與主要技術 1.件開發工具   游戲程序開發工具有很多,在不同游戲平臺上有不同的開發工具。在個人計算機上,可以用目前流性的軟件開發工具,比如:C,C++,VC++,Delphi,C++ Builder等。由于Windows操作系統的普及和其強大的多媒體功能,越來越多的游戲支持Windows操作系統。由于VC是微軟的產品,用它來編寫Windows程序有強大的程序接口和豐富的開發資源的支持,加之VC嚴謹的內存管理,在堆棧上良好的分配處理,生成代碼的體積小,穩定性高的優點,所以VC++就成為目前游戲的主流開發工具。 2.DirectX組件的知識   談到Windows系統下的游戲開發,我們就要說一下微軟的DirectX SDK。   Windows系統有一個主要優點是應用程序和設備之間的獨立性。然而應用程序的設備無關性是通過犧牲部分速度和效率的到的,Windows在硬件和軟件間添加了中間抽象層,通過這些中間層我們的應用程序才能在不同的硬件上游刃有余。但是,我們因此而不能完全利用硬件的特征來獲取最大限度的運算和顯示速度。這一點在編寫Windows游戲時是致命的,DirectX便是為解決這個問題而設計的。DirectX由快速的底層庫組成并且沒有給游戲設計添加過多的約束。微軟的DirectX軟件開發工具包(SDK)提供了一套優秀的應用程序編程接口(APIs),這個編程接口可以提供給你開發高質量、實時的應用程序所需要的各種資源。   DirectX的6個組件分別是:     DirectDraw: 使用頁面切換的方法實現動畫,它不僅可以訪問系統內存,還可以訪問顯示內存。     Direct3D: 提供了3D硬件接口。     DirectSound: 立體聲和3D聲音效果,同時管理聲卡的內存。     DirectPlay: 支持開發多人網絡游戲,并能處理游戲中網絡之間的通信問題。     DirectInput: 為大量的設備提供輸入支持。     DirectSetup: 自動安裝DirectX驅動程序。   隨著DirectX版本的提高,還增加了音樂播放的DirectMusic。 3.AlphaBlend 技術   現在許多游戲為了達到光影或圖象的透明效果都會采用AlphaBlend 技術。所謂AlphaBlend技術,其實就是按照"Alpha"混合向量的值來混合源像素和目標像素,一般用來處理半透明效果。在計算機中的圖象可以用R(紅色),G(綠色),B(藍色)三原色來表示。假設一幅圖象是A,另一幅透明的圖象是B,那么透過B去看A,看上去的圖象C就是B和A的混合圖象,設B圖象的透明度為alpha(取值為0-1,0為完全透明,1為完全不透明),Alpha混合公式如下:     R(C)=alpha*R(B)+(1-alpha)*R(A)     G(C)=alpha*G(B)+(1-alpha)*G(A)     B(C)=alpha*B(B)+(1-alpha)*B(A)   R(x)、G(x)、B(x)分別指顏色x的RGB分量原色值。從上面的公式可以知道,Alpha其實是一個決定混合透明度的數值。應用Alpha混合技術,可以實現游戲中的許多特效,比如火光、煙霧、陰影、動態光源等半透明效果。 4.A*算法   在許多游戲中要用鼠標控制人物運動,而且讓人物從目前的位置走到目標位置應該走最短的路徑。這就要用到最短路徑搜索算法即A*算法了。   A*算法實際是一種啟發式搜索,所謂啟發式搜索,就是利用一個估價函數評估每次的的決策的價值,決定先嘗試哪一種方案。如果一個估價函數可以找出最短的路徑,我們稱之為可采納性。A*算法是一個可采納的最好優先算法。A*算法的估價函數可表示為:     f(n) = g(n) + h(n)   這里,f(n)是節點n的估價函數,g(n)是起點到終點的最短路徑值,h(n)是n到目標的最斷路經的啟發值。由于A*算法比較復雜,限于篇幅,在此簡單介紹一下,具體理論朋友們可以看人工智能方面的書籍了解詳細的情況。   其它技術還有粒子系統,音頻與視頻的調用,圖象文件的格式與信息存儲等,大家可以在學好DirectX的基礎上逐漸學習更多的技術。 (二)游戲的具體制作 1.地圖編輯器的制作   RPG游戲往往要有大量的場景,場景中根據需要可以有草地,湖泊,樹木,房屋,家具等道俱,由于一個游戲需要很多場景且地圖越來越大,為了節省空間,提高圖象文件的可重用性,RPG游戲的畫面采用很多重復的單元(可以叫做“圖塊”)所構成的,這就要用到地圖編輯器了。我們在制作游戲引擎前,要完成地圖編輯器的制作。在 RPG游戲里,場景的構成,是圖塊排列順序的記錄。首先制定一個場景構成文件的格式,在這個文件里記錄構成場景所需要的圖塊的排列順序,因為我們已經為每個圖塊建立了索引,所以只需要記錄這些索引就可以了。一個場景的構成,是分成幾層來完成的:地面,建筑和植物,家具擺設,和在場景中活動的人物或者物體(比如飄揚的旗幟),按照一定的順序把它們依次顯示到屏幕上,就形成了一個豐富多采的場景。我們可以用數組來表示地圖場景的生成過程。
            MapData[X][Y]; //地圖數據,X表示地圖寬度,Y表示地圖高度 
            Picture[num]; //道具的圖片,num表示道具的總數 void MakeBackGround() //生成場景函數 
            {  
                
            int n;  
                
            forint i=0; i<Y; i++//共Y行  
                   forint j=0; j<X; j++//共X列  
                     {   
                        n
            =MapData[ i ][ j ]; //取得該位置的道具編號   
                        Draw( j*32, i*32, Picture[n]); //在此位置(j*32,i*32)畫道具  
                      }
             
            }
             
            2.游戲的模塊的劃分   游戲按功能分為:消息處理系統、場景顯示及行走系統、打斗系統三大主要部分。其中又以消息處理系統為核心模塊,其余部分緊緊圍繞它運行。 一:消息處理系統   消息處理系統是游戲的核心部分。游戲用到的消息處理系統先等待消息,然后根據收到的消息轉到相應的函數進行處理。比如:主角碰到敵人后,我們就讓程序產生‘打斗消息’,消息處理系統收到這個消息后就會馬上轉到打斗模塊中去。消息處理的大體框架如下:
            //定義程序中要用到的變量 
            DWORD Message; //消息變量 
            WinMain() //進入程序 
            {  
                初始化主窗口;  
                初始化DirectDraw環境,并調入程序需要的圖形、地圖數據;  
                
            while1 ) //消息循環  
                {   
                    
            switch( Message )   
                       
            {    
                          
            case 行走消息: 行走模塊();                case 打斗消息:打斗模塊();                case 事件消息: 事件模塊();   
                        }
              
                 }
             
            }
            二:場景顯示及行走系統   作為RPG游戲,其所有事件的發生幾乎都是和場景有關,例如:不同的地方會碰到不同的敵人、與不同的人對話得知不同的事情等。鑒于這部分的重要性,我們可再將它劃分為:背景顯示、行走 和 事件發生 三個子模塊,分別處理各自的功能。下面進行具體分析。 (一)背景顯示   程序運行后,先讀取前面地圖編輯器制作的場景所需要的圖塊的排列順序,按照排列順序將圖象拼成一個完整的場景,一般做法是:在內存中開辟一到兩個屏幕緩存區,事先把即將顯示的圖象數據準備在緩存區內,然后一次性搬家:把它們傳送到真正的屏幕緩沖區內。   游戲用到的圖片則事先制作好并存于另外的圖形文件中。地圖編輯器制作的場景文件僅僅是對應的數據,而不是真正的圖片。在游戲中生成場景就是地圖編輯的逆過程,一個是根據場景生成數據,而另一個是根據數據生成場景。 (二)行走   要讓主角在場景中行走,至少要有上、下、左、右四個行走方向,每個方向4幅圖(站立、邁左腿、邁右腿、邁左腿),如圖:游戲中一定要將圖片的背景設為透明,這樣在畫人物的時候就不會覆蓋上背景色了(這一技術DirectDraw中只要用SetColorKey()函數將原圖片背景色過濾掉就行了)。我們讓主角位置不動,而使場景移動,即采用滾屏技術來實現角色在場景上移動。這樣角色一直保持在屏幕的正中間,需要做的工作只是根據行走方向和步伐不停變換圖片而已。行走時的障礙物判斷也是每一個場景中必定要有的,有一些道具如樹木、房屋等是不可跨越的。對此我主要用一個二維數組來對應一個場景,每一個數組值代表場景的一小格(見圖3)。有障礙的地方,該數組的對應值為1,可通過的地方的值為0。 (三)事件發生   事件發生原理就是把相應事件的序號存儲在地圖的某些格子中,當主角一踏入這個格子就會觸發對應事件。例如:在游戲開始時,主角是在他的家里。他要是想出去的話,就需要執行場景切換這個處理函數。我們假定該事件的編號為001,那么在地圖上把家門外路口處的格子值設為001。這樣主角走到路口時,編號為001的場景切換函數就會被觸發,于是主角便到了下一個場景中。程序具體如下:
            void MessageLoop( int Msg ) //消息循環 
            {
                    
            switch( Msg )  
                     
            {
                           
            char AddressName[16]; //數組AddressName[16]用來存儲主角所在地點的名稱   
                           case ADDRESS == 001// 由ADDRESS的值決定場景值(出門)   
                           ScreenX=12
                         ScreenY
            =0//初始化游戲背景位置                Hero.x=360; 
                         Hero.y=80;//主角坐標   
                           Move();//主角移動函數   
                        
            //以下程序用來顯示主角所在地點   
                           sprintf(AddressName,"下一幅游戲場景的名稱");
                         PrintText(lpDDSPrimary, 
            280330,AddressName , RGB(255,255,255));//在屏幕上顯示出場景的名稱
                          break;
                     }

            }
            三:打斗系統   絕大多數的RPG都是有戰斗存在的,因此,打斗系統就成為RPG系統中很重要的一環。有不少RPG游戲采用回合制打斗方式,因為實現起來較為簡單。和打斗緊密相關的是升級,通常在一場戰斗結束后,主角的經驗值都會增加。而當經驗值到達一定程度時,角色就升級了。   上面我簡要的介紹了角色扮演游戲的制作,由于寫這篇文章的目的是讓讀者對角色扮演游戲的制作有一個基本的了解,所以讀者朋友們可以研究相關資料

            posted @ 2008-07-18 18:10 Niino 閱讀(131) | 評論 (0)編輯 收藏
             軟件測試軟件開發過程的重要組成部分,是用來確認一個程序的品質或性能是否符合開發之前所提出的一些要求。軟件測試就是在軟件投入運行前,對軟件需求分析、設計規格說明和編碼的最終復審,是軟件質量保證的關鍵步驟。軟件測試是為了發現錯誤而執行程序的過程。軟件測試在軟件生存期中橫跨兩個階段:通常在編寫出每一個模塊之后就對它做必要的測試(稱為單元測試)。編碼和單元測試屬于軟件生存期中的同一個階段。在結束這個階段后對軟件系統還要進行各種綜合測試,這是軟件生存期的另一個獨立階段,即測試階段。

            一、軟件測試的目的

             

                  軟件測試的目的,第一是確認軟件的質量,其一方面是確認軟件做了你所期望的事情(Do the right thing),另一方面是確認軟件以正確的方式來做了這個事件(Do it right)。

                  第二是提供信息,比如提供給開發人員或程序經理的反饋信息,為風險評估所準備的信息。

                  第三軟件測試不僅是在測試軟件產品的本身,而且還包括軟件開發的過程。如果一個軟件產品開發完成之后發現了很多問題,這說明此軟件開發過程很可能是有缺陷的。因此軟件測試的第三個目的是保證整個軟件開發過程是高質量的。

                  軟件質量是由幾個方面來衡量的:一、在正確的時間用正確的的方法把一個工作做正確(Doing the right things right at the right time.)。二、符合一些應用標準的要求,比如不同國家的用戶不同的操作習慣和要求,項目工程中的可維護性、可測試性等要求。三、質量本身就是軟件達到了最開始所設定的要求,而代碼的優美或精巧的技巧并不代表軟件的高質量(Quality is defined as conformance to requirements, not as “goodness” or “elegance”.)。四、質量也代表著它符合客戶的需要(Quality also means “meet customer needs”.)。作為軟件測試這個行業,最重要的一件事就是從客戶的需求出發,從客戶的角度去看產品,客戶會怎么去使用這個產品,使用過程中會遇到什么樣的問題。只有這些問題都解決了,軟件產品的質量才可以說是上去了。

                  測試人員在軟件開發過程中的任務:

                  1、尋找Bug;
                  2、避免軟件開發過程中的缺陷;
                  3、衡量軟件的品質;
                  4、關注用戶的需求。

                  總的目標是:確保軟件的質量。

            二、軟件測試的原則


                  軟件測試從不同的角度出發會派生出兩種不同的測試原則,從用戶的角度出發,就是希望通過軟件測試能充分暴露軟件中存在的問題和缺陷,從而考慮是否可以接受該產品,從開發者的角度出發,就是希望測試能表明軟件產品不存在錯誤,已經正確地實現了用戶的需求,確立人們對軟件質量的信心。

                  為了達到上述的原則,那么需要注意以下幾點:
            1.應當把“盡早和不斷的測試”作為開發者的座右銘
            2.程序員應該避免檢查自己的程序,測試工作應該由獨立的專業的軟件測試機構來完。
            3.設計測試用例時應該考慮到合法的輸入和不合法的輸入以及各種邊界條件,特殊情況要制造極端狀態和意外狀態,比如網絡異常中斷、電源斷電等情況。
            4.一定要注意測試中的錯誤集中發生現象,這和程序員的編程水平和習慣有很大的關系。
            5.對測試錯誤結果一定要有一個確認的過程,一般有A測試出來的錯誤,一定要有一個B來確認,嚴重的錯誤可以召開評審會進行討論和分析。
            6.制定嚴格的測試計劃,并把測試時間安排的盡量寬松,不要希望在極短的時間內完成一個高水平的測試。
            7.回歸測試的關聯性一定要引起充分的注意,修改一個錯誤而引起更多的錯誤出現的現象并不少見。
            8.妥善保存一切測試過程文檔,意義是不言而喻的,測試的重現性往往要靠測試文檔。


            三、軟件測試的對象

              軟件測試并不等于程序測試。軟件測試應該貫穿整個軟件定義與開發整個期間。因此需求分析、概要設計、詳細設計以及程序編碼等各階段所得到的文檔,包括需求規格說明、概要設計規格說明、詳細設計規格說明以及源程序,都應該是軟件測試的對象。

              在對需求理解與表達的正確性、設計與表達的正確性、實現的正確性以及運行的正確性的驗證中,任何一個環節發生了問題都可能在軟件測試中表現出來。 


            四、軟件測試方法
             
             
            軟件測試的基本方法
            單元測試的基本方法
            綜合測試的基本方法
            確認測試的基本方法
            系統測試的基本方法
            軟件測試的基本方法

              軟件測試的方法和技術是多種多樣的。
              對于軟件測試技術,可以從不同的角度加以分

              從是否需要執行被測軟件的角度,可分為靜態測試和動態測試。
              從測試是否針對系統的內部結構和具體實現算法的角度來看,可分為白盒測試黑盒測試

            1、黑盒測試

              黑盒測試也稱功能測試數據驅動測試,它是在已知產品所應具有的功能,通過測試來檢測每個功能是否都能正常使用,在測試時,把程序看作一個不能打開的黑盆子,在完全不考慮程序內部結構和內部特性的情況下,測試者在程序接口進行測試,它只檢查程序功能是否按照需求規格說明書的規定正常使用,程序是否能適當地接收輸入數鋸而產生正確的輸出信息,并且保持外部信息(如數據庫文件)的完整性。黑盒測試方法主要有等價類劃分、邊值分析、因果圖、錯誤推測等,主要用于軟件確認測試。 “黑盒”法著眼于程序外部結構、不考慮內部邏輯結構、針對軟件界面和軟件功能進行測試。“黑盒”法是窮舉輸入測試,只有把所有可能的輸入都作為測試情況使用,才能以這種方法查出程序中所有的錯誤。實際上測試情況有無窮多個,人們不僅要測試所有合法的輸入,而且還要對那些不合法但是可能的輸入進行測試。

            2、白盒測試

              白盒測試也稱結構測試邏輯驅動測試,它是知道產品內部工作過程,可通過測試來檢測產品內部動作是否按照規格說明書的規定正常進行,按照程序內部的結構測試程序,檢驗程序中的每條通路是否都有能按預定要求正確工作,而不顧它的功能,白盒測試的主要方法有邏輯驅動、基路測試等,主要用于軟件驗證。

              “白盒”法全面了解程序內部邏輯結構、對所有邏輯路徑進行測試。“白盒”法是窮舉路徑測試。在使用這一方案時,測試者必須檢查程序的內部結構,從檢查程序的邏輯著手,得出測試數據。貫穿程序的獨立路徑數是天文數字。但即使每條路徑都測試了仍然可能有錯誤。第一,窮舉路徑測試決不能查出程序違反了設計規范,即程序本身是個錯誤的程序。第二,窮舉路徑測試不可能查出程序中因遺漏路徑而出錯。第三,窮舉路徑測試可能發現不了一些與數據相關的錯誤。

            3.ALAC(Act-like-a-customer)測試

             

              ALAC測試是一種基于客戶使用產品的知識開發出來的測試方法。ALAC測試是基于復雜的軟件產品有許多錯誤的原則。最大的受益者是用戶,缺陷查找和改正將針對哪些客戶最容易遇到的錯誤。

            單元測試的基本方法

            單元測試的對象是軟件設計的最小單位模塊。單元測試的依據是詳細設描述,單元測試應對模塊內所有重要的控制路徑設計測試用例,以便發現模塊內部的錯誤。單元測試多采用白盒測試技術,系統內多個模塊可以并行地進行測試。
            單元測試任務

              單元測試任務包括:1 模塊接口測試;2 模塊局部數據結構測試;3 模塊邊界條件測試;4 模塊中所有獨立執行通路測試;5 模塊的各條錯誤處理通路測試。

              模塊接口測試是單元測試的基礎。只有在數據能正確流入、流出模塊的前提下,其他測試才有意義。測試接口正確與否應該考慮下列因素:
               1 輸入的實際參數與形式參數的個數是否相同;
               2 輸入的實際參數與形式參數的屬性是否匹配;
               3 輸入的實際參數與形式參數的量綱是否一致;
               4 調用其他模塊時所給實際參數的個數是否與被調模塊的形參個數相同;
               5 調用其他模塊時所給實際參數的屬性是否與被調模塊的形參屬性匹配;
               6調用其他模塊時所給實際參數的量綱是否與被調模塊的形參量綱一致;
               7 調用預定義函數時所用參數的個數、屬性和次序是否正確;
               8 是否存在與當前入口點無關的參數引用;
               9 是否修改了只讀型參數;
               10 對全程變量的定義各模塊是否一致;
               11是否把某些約束作為參數傳遞。

              如果模塊內包括外部輸入輸出,還應該考慮下列因素:
               1 文件屬性是否正確;
               2 OPEN/CLOSE語句是否正確;
               3 格式說明與輸入輸出語句是否匹配;
               4緩沖區大小與記錄長度是否匹配;
               5文件使用前是否已經打開;
               6是否處理了文件尾;
               7是否處理了輸入/輸出錯誤;
               8輸出信息中是否有文字性錯誤;

              檢查局部數據結構是為了保證臨時存儲在模塊內的數據在程序執行過程中完整、正確。局部數據結構往往是錯誤的根源,應仔細設計測試用例,力求發現下面幾類錯誤:
               1 不合適或不相容的類型說明;
               2變量無初值;
               3變量初始化或省缺值有錯;
               4不正確的變量名(拼錯或不正確地截斷);
               5出現上溢、下溢和地址異常。

              除了局部數據結構外,如果可能,單元測試時還應該查清全局數據(例如FORTRAN的公用區)對模塊的影響。

              在模塊中應對每一條獨立執行路徑進行測試,單元測試的基本任務是保證模塊中每條語句至少執行一次。此時設計測試用例是為了發現因錯誤計算、不正確的比較和不適當的控制流造成的錯誤。此時基本路徑測試和循環測試是最常用且最有效的測試技術。計算中常見的錯誤包括:
               1 誤解或用錯了算符優先級;
               2混合類型運算;
               3變量初值錯;
               4精度不夠;
               5表達式符號錯。

              比較判斷與控制流常常緊密相關,測試用例還應致力于發現下列錯誤:
               1不同數據類型的對象之間進行比較;
               2錯誤地使用邏輯運算符或優先級;
               3因計算機表示的局限性,期望理論上相等而實際上不相等的兩個量相等;
               4比較運算或變量出錯;
               5循環終止條件或不可能出現;
               6迭代發散時不能退出;
               7錯誤地修改了循環變量。

              一個好的設計應能預見各種出錯條件,并預設各種出錯處理通路,出錯處理通路同樣需要認真測試,測試應著重檢查下列問題:
               1輸出的出錯信息難以理解;
               2記錄的錯誤與實際遇到的錯誤不相符;
               3在程序自定義的出錯處理段運行之前,系統已介入;
               4異常處理不當;
               5錯誤陳述中未能提供足夠的定位出錯信息。

              邊界條件測試是單元測試中最后,也是最重要的一項任務。眾的周知,軟件經常在邊界上失效,采用邊界值分析技術,針對邊界值及其左、右設計測試用例,很有可能發現新的錯誤。

            單元測試過程

              一般認為單元測試應緊接在編碼之后,當源程序編制完成并通過復審和編譯檢查,便可開始單元測試。測試用例的設計應與復審工作相結合,根據設計信息選取測試數據,將增大發現上述各類錯誤的可能性。在確定測試用例的同時,應給出期望結果。

              應為測試模塊開發一個驅動模塊(driver)和(或)若干個樁模塊(stub),下圖顯示了一般單元測試的環境。驅動模塊在大多數場合稱為“主程序”,它接收測試數據并將這些數據傳遞到被測試模塊,被測試模塊被調用后,“主程序”打印“進入-退出”消息

              驅動模塊和樁模塊是測試使用的軟件,而不是軟件產品的組成部分,但它需要一定的開發費用。若驅動和樁模塊比較簡單,實際開銷相對低些。遺憾的是,僅用簡單的驅動模塊和樁模塊不能完成某些模塊的測試任務,這些模塊的單元測試只能采用下面討論的綜合測試方法。

              提高模塊的內聚度可簡化單元測試,如果每個模塊只能完成一個,所需測試用例數目將顯著減少,模塊中的錯誤也更容易發現。

            綜合測試的基本方法


               時常有這樣的情況發生,每個模塊都能單獨工作,但這些模塊集成在一起之后卻不能正常工作。主要原因是,模塊相互調用時接口會引入許多新問題。例如,數據經過接口可能丟失;一個模塊對另一模塊可能造成不應有的影響;幾個子功能組合起來不能實現主功能;誤差不斷積累達到不可接受的程度;全局數據結構出現錯誤,等等。綜合測試是組裝軟件的系統測試技術,按設計要求把通過單元測試的各個模塊組裝在一起之后,進行綜合測試以便發現與接口有關的各種錯誤。

              某設計人員習慣于把所有模塊按設計要求一次全部組裝起來,然后進行整體測試,這稱為非增量式集成。這種方法容易出現混亂。因為測試時可能發現一大堆錯誤,為每個錯誤定位和糾正非常困難,并且在改正一個錯誤的同時又可能引入新的錯誤,新舊錯誤混雜,更難斷定出錯的原因和位置。與之相反的是增量式集成方法,程序一段一段地擴展,測試的范圍一步一步地增大,錯誤易于定位和糾正,界面的測試亦可做到完全徹底。下面討論兩種增量式集成方法。

            1 自頂向下集成

              自頂向下集成是構造程序結構的一種增量式方式,它從主控模塊開始,按照軟件的控制層次結構,以深度優先或廣度優先的策略,逐步把各個模塊集成在一起。深度優先策略首先是把主控制路徑上的模塊集成在一起,至于選擇哪一條路徑作為主控制路徑,這多少帶有隨意性,一般根據問題的特性確定。以下圖為例,若選擇了最左一條路徑,首先將模塊M1,M2,M5和M8集成在一起,再將M6集成起來,然后考慮中間和右邊的路徑。廣度優先策略則不然,它沿控制層次結構水平地向下移動。仍以下圖為例,它首先把M2、M3和M4與主控模塊集成在一起,再將M5和M6 和其他模塊集資集成起來。

              自頂向下綜合測試的具體步驟為:
               1 以主控模塊作為測試驅動模塊,把對主控模塊進行單元測試時引入的所有樁模塊用實際模塊替代;
               2 依據所選的集成策略(深度優先或廣度優先),每次只替代一個樁模塊;
               3 每集成一個模塊立即測試一遍;
               4 只有每組測試完成后,才著手替換下一個樁模塊;
               5 為避免引入新錯誤,須不斷地進行回歸測試(即全部或部分地重復已做過的測試)。
             

               從第二步開始,循環執行上述步驟,直至整個程序結構構造完畢。下圖中,實線表示已部分完成的結構,若采用深度優先策略,下一步將用模塊M7替換樁模塊S7,當然M7本身可能又帶有樁模塊,隨后將被對應的實際模塊一一替代。

              自頂向下集成的優點在于能盡早地對程序的主要控制和決策機制進行檢驗,因此較早地發現錯誤。缺點是在測試較高層模塊時,低層處理采用樁模塊替代,不能反映真實情況,重要數據不能及時回送到上層模塊,因此測試并不充分。解決這個問題有幾種辦法,第一種是把某些測試推遲到用真實模塊替代樁模塊之后進行,第二種是開發能模擬真實模塊的樁模塊;第三種是自底向上集成模塊。第一種方法又回退為非增量式的集成方法,使錯誤難于定位和糾正,并且失去了在組裝模塊時進行一些特定測試的可能性;第二種方法無疑要大大增加開銷;第三種方法比較切實可行,下面專門討論。

            2自底向上集成

              自底向上測試是從“原子”模塊(即軟件結構最低層的模塊)開始組裝測試,因測試到較高層模塊時,所需的下層模塊功能均已具備,所以不再需要樁模塊。

              自底向上綜合測試的步驟分為:
               1 把低層模塊組織成實現某個子功能的模塊群(cluster);
               2 開發一個測試驅動模塊,控制測試數據的輸入和測試結果的輸出;
               3 對每個模塊群進行測試;
               4 刪除測試使用的驅動模塊,用較高層模塊把模塊群組織成為完成更大功能的新模塊群。

              從第一步開始循環執行上述各步驟,直至整個程序構造完畢。

              下圖說明了上述過程。首先“原子”模塊被分為三個模塊群,每個模塊群引入一個驅動模塊進行測試。因模塊群1、模塊群2中的模塊均隸屬于模塊Ma,因此在驅動模塊D1、D2去掉后,模塊群1與模塊群2直接與Ma接口,這時可對MaD3被去掉后,M3與模塊群3直接接口,可對Mb進行集成測試,最后Ma、Mb和 Mc全部集成在一起進行測試。

             

               自底向上集成方法不用樁模塊,測試用例的設計亦相對簡單,但缺點是程序最后一個模塊加入時才具有整體形象。它與自頂向綜合測試方法優缺點正好相反。因此,在測試軟件系統時,應根據軟件的特點和工程的進度,選用適當的測試策略,有時混和使用兩種策略更為有效,上層模塊用自頂向下的方法,下層模塊用自底向上的方法。

              此外,在綜合測試中尤其要注意關鍵模塊,所謂關鍵模塊一般都具有下述一或多個特征:①對應幾條需求;②具有高層控制功能;③復雜、易出錯;④有特殊的性能要求。關鍵模塊應盡早測試,并反復進行回歸測試。

            確認測試的基本方法
               通過綜合測試之后,軟件已完全組裝起來,接口方面的錯誤也已排除,軟件測試的最后一步確認測試即可開始。確認測試應檢查軟件能否按合同要求進行工作,即是否滿足軟件需求說明書中的確認標準。

            1. 確認測試標準

              實現軟件確認要通過一系列墨盒測試。確認測試同樣需要制訂測試計劃和過程,測試計劃應規定測試的種類和測試進度,測試過程則定義一些特殊的測試用例,旨在說明軟件與需求是否一致。無是計劃還是過程,都應該著重考慮軟件是否滿足合同規定的所有功能和性能,文檔資料是否完整、準確人機界面和其他方面(例如,可移植性、兼容性、錯誤恢復能力和可維護性等)是否令用戶滿意。

              確認測試的結果有兩種可能,一種是功能和性能指標滿足軟件需求說明的要求,用戶可以接受;另一種是軟件不滿足軟件需求說明的要求,用戶無法接受。項目進行到這個階段才發現嚴重錯誤和偏差一般很難在預定的工期內改正,因此必須與用戶協商,尋求一個妥善解決問題的方法。

            2. 配置復審

              確認測試的另一個重要環節是配置復審。復審的目的在于保證軟件配置齊全、分類有序,并且包括軟件維護所必須的細節。

            3. α、β測試

              事實上,軟件開發人員不可能完全預見用戶實際使用程序的情況。例如,用戶可能錯誤的理解命令,或提供一些奇怪的數據組合,亦可能對設計者自認明了的輸出信息迷惑不解,等等。因此,軟件是否真正滿足最終用戶的要求,應由用戶進行一系列“驗收測試”。驗收測試既可以是非正式的測試,也可以有計劃、有系統的測試。有時,驗收測試長達數周甚至數月,不斷暴露錯誤,導致開發延期。一個軟件產品,可能擁有眾多用戶,不可能由每個用戶驗收,此時多采用稱為α、β測試的過程,以期發現那些似乎只有最終用戶才能發現的問題。

              α測試是指軟件開發公司組織內部人員模擬各類用戶行對即將面市軟件產品(稱為α版本)進行測試,試圖發現錯誤并修正。α測試的關鍵在于盡可能逼真地模擬實際運行環境和用戶對軟件產品的操作并盡最大努力涵蓋所有可能的 用戶操作方式。經過α測試調整的軟件產品稱為β版本。緊隨其后的β測試是指軟件開發公司組織各方面的典型用戶在日常工作中實際使用β版本,并要求用戶報告異常情況、提出批評意見。然后軟件開發公司再對β版本進行改錯和完善。

            系統測試的基本方法

               計算機軟件是基于計算機系統的一個重要組成部分,軟件開發完畢后應與系統中其它成分集成在一起,此時需要進行一系列系統集成和確認測試。對這些測試的詳細討論已超出軟件工程的范圍,這些測試也不可能僅由軟件開發人員完成。在系統測試之前,軟件工程師應完成下列工作:
               (1) 為測試軟件系統的輸入信息設計出錯處理通路;
               (2) 設計測試用例,模擬錯誤數據和軟件界面可能發生的錯誤,記錄測試結果,為系統測試提供經驗和幫助;
               (3) 參與系統測試的規劃和設計,保證軟件測試的合理性。

              系統測試應該由若干個不同測試組成,目的是充分運行系統,驗證系統各部件是否都能政黨工作并完成所賦予的任務。下面簡單討論幾類系統測試。

            1、恢復測試

              恢復測試主要檢查系統的容錯能力。當系統出錯時,能否在指定時間間隔內修正錯誤并重新啟動系統。恢復測試首先要采用各種辦法強迫系統失敗,然后驗證系統是否能盡快恢復。對于自動恢復需驗證重新初始化(reinitialization)、檢查點(checkpointing mechanisms)、數據恢復(data recovery)和重新啟動 (restart)等機制的正確性;對于人工干預的恢復系統,還需估測平均修復時間,確定其是否在可接受的范圍內。

            2、安全測試

              安全測試檢查系統對非法侵入的防范能力。安全測試期間,測試人員假扮非法入侵者,采用各種辦法試圖突破防線。例如,①想方設法截取或破譯口令;②專門定做軟件破壞系統的保護機制;③故意導致系統失敗,企圖趁恢復之機非法進入;④試圖通過瀏覽非保密數據,推導所需信息,等等。理論上講,只要有足夠的時間和資源,沒有不可進入的系統。因此系統安全設計的準則是,使非法侵入的代價超過被保護信息的價值。此時非法侵入者已無利可圖。

            3、強度測試

              強度測試檢查程序對異常情況的抵抗能力。強度測試總是迫使系統在異常的資源配置下運行。例如,①當中斷的正常頻率為每秒一至兩個時,運行每秒產生十個中斷的測試用例;②定量地增長數據輸入率,檢查輸入子功能的反映能力;③運行需要最大存儲空間(或其他資源)的測試用例;④運行可能導致虛存操作系統崩潰或磁盤數據劇烈抖動的測試用例,等等。

            4、 性能測試

              對于那些實時和嵌入式系統,軟件部分即使滿足功能要求,也未必能夠滿足性能要求,雖然從單元測試起,每一測試步驟都包含性能測試,但只有當系統真正集成之后,在真實環境中才能全面、可靠地測試運行性能系統性能測試是為了完成這一任務。性能測試有時與強度測試相結合,經常需要其他軟硬件的配套支持。

            五、軟件測試的類型

            常見的軟件測試類型有:

                  BVT (Build Verification Test)

                  BVT是在所有開發工程師都已經檢入自己的代碼,項目組編譯生成當天的版本之后進行,主要目的是驗證最新生成的軟件版本在功能上是否完整,主要的軟件特性是否正確。如無大的問題,就可以進行相應的功能測試。BVT優點是時間短,驗證了軟件的基本功能。缺點是該種測試的覆蓋率很低。因為運行時間短,不可能把所有的情況都測試到。

                  Scenario Tests(基于用戶實際應用場景的測試)

                  在做BVT、功能測試的時候,可能測試主要集中在某個模塊,或比較分離的功能上。當用戶來使用這個應用程序的時候,各個模塊是作為一個整體來使用的,那么在做測試的時候,就需要模仿用戶這樣一個真實的使用環境,即用戶會有哪些用法,會用這個應用程序做哪些事情,操作會是一個怎樣的流程。加了這些測試用例后,再與BVT、功能測試配合,就能使軟件整體都能符合用戶使用的要求。Scenario Tests優點是關注了用戶的需求,缺點是有時候難以真正模仿用戶真實的使用情況。

                  Smoke Test

                  在測試中發現問題,找到了一個Bug,然后開發人員會來修復這個Bug。這時想知道這次修復是否真的解決了程序的Bug,或者是否會對其它模塊造成影響,就需要針對此問題進行專門測試,這個過程就被稱為Smoke Test。在很多情況下,做Smoke Test是開發人員在試圖解決一個問題的時候,造成了其它功能模塊一系列的連鎖反應,原因可能是只集中考慮了一開始的那個問題,而忽略其它的問題,這就可能引起了新的Bug。Smoke Test優點是節省測試時間,防止build失敗。缺點是覆蓋率還是比較低。

                  此外,Application Compatibility Test(兼容性測試),主要目的是為了兼容第三方軟件,確保第三方軟件能正常運行,用戶不受影響。Accessibility Test(軟件適用性測試),是確保軟件對于某些有殘疾的人士也能正常的使用,但優先級比較低。其它的測試還有Functional Test(功能測試)、Security Test(安全性測試)、Stress Test(壓力測試)、Performance Test(性能測試)、Regression Test(回歸測試)、Setup/Upgrade Test(安裝升級測試)等。

            六、軟件測試支持工具


                  一些受軟件開發人員歡迎的軟件測試工具為軟件測試提供了強有力的支持。本文將介紹美國Rational公司的著名套裝軟件SQA和Pure Atria公司極具特色的Purify。

                  SQA SuiteSQA直接支持對客戶/服務器應用軟件的測試,它的一個重要特點是可以自動驅動被測程序的運行。SQA可以自動記錄和重放程序執行過程,從而實現了對測試進行"復查"的自動化

                  由于測試是一個需要反復進行的過程,常常要數十次甚至數百次地重復。因此,這一特性大大地提高了軟件"再測試"(Re-Test)和"回歸測試"(Regression)的自動化程度,把測試人員從繁雜的、重復性的手工測試中解脫出來,從而顯著地提高軟件測試效率。

                  除了這個最基本的自動錄放功能外,它還提供了一系列的輔助支持功能,比如,

              · 被錄制的程序執行過程可以被自動轉換成具有良好可讀性的高級語言程序,從而使這個測試驅動程序可以由測試人員根據測試需要進行必要的修改,甚至完全用手工方式編制。

              ·自動記錄和分析比較測試的執行結果。不論是簡單的正文方式的輸出結果,還是任意的圖表、聲音、動畫、圖形用戶界面(GUI)中的任一構件,都可以根據測試人員的指定被自動記錄在測試結果庫中,并可對兩次測試的結果自動地進行比較,指出其差異部分。此項功能無疑對"自動查找錯誤"很有幫助。

              ·調節和設定事件的發生時間和速度。

              ·基本的測試庫管理功能。

              此外,SQA還支持軟件測試人員進行以下工作:

              ·制定測試計劃和測試大綱,并將這些文檔按照自然的樹狀結構分層地管理起來,并據此控制和驅動整個測試過程。

              ·不僅能夠自動記錄各類測試結果,而且對其進行修改,從而使得測試人員可以在程序運行結果尚有許多錯誤的情況下,通過對所記錄下的結果做適當修正來獲得理想的"期望結果" ,為測試結果的自動比較奠定基礎。

              ·測試問題報告的記錄與管理。

                  總之,SQA Suite提供了一個比較完整的測試平臺,以支持軟件測試的各種基本活動,包括測試計劃與測試大綱的制定、回歸測試的自動化、測試結果的分析比較、軟件問題報告的生成與自動分發和控制等。對于許多應用軟件的開發無疑是個有力的測試支持工具。

                  Purify是原PureAtria公司(現已經與美國Rational公司合并,改名為美國Rational公司)于90年代初率先推出的專門用于檢測程序中種種內存使用錯誤的軟件工具。幾乎所有使用過C語言開發軟件的程序員都會有這樣的體會,C語言中使用極為靈活的指針給程序員帶來了很大便利,但同時也制造了許多的麻煩。由于指針使用不當而引起的錯誤通常是最難發現的,同時也是最難定位的一類錯誤。而Purify對多種常見的內存使用錯誤的檢錯能力和準確的定位,受到廣大軟件開發人員的青睞。

                  Purify可以自動識別出二十多種內存使用錯誤,包括

              ·未初始化的局部變量

              ·未申請的內存

              ·使用已釋放的內存

              ·數組越界

              ·內存丟失

              ·文件描述問題

              ·棧溢出問題

              ·棧結構邊界錯誤等

                  在下面的例子中,暗藏著兩個內存使用錯誤。第一行為指針數組pp申請的空間尺寸不對。這類錯誤往往不易發現,因為在C語言中,一些"輕微"的內存越界可能被系統所容忍。但這往往是導致更嚴重錯誤的根源。例如,可能破壞其它數據區等。最后一行的錯誤是在釋放pp 之前沒有釋放賦予它的字符串空間,從而把它們"丟失"了。這類錯誤猶如慢性自殺,它會逐漸消耗掉內存,降低系統的運行效率,直到完全崩潰。而真正的問題在于,這些程序中的"惡性腫瘤"用常規的測試手段和調試工具是極難發現和加以定位的。Purify則在此充分顯示了它的強大功效,所到之處,即對所測試過的情況,上述各種常見的內存錯誤都可以被一一揭露出來,并且準確地指出錯誤的類型和位置。從而大大地提高了測試和糾錯的效率,提高了軟件的可靠性。

              …/"to get 10 words and print them out"/

              if(!(pp=(char**)malloc(10))){

              /*Size should be 10*sizeof(char*)*/

              printf("Out of memory.\n");

              exit(-1);

              }

              for(i=0;i<10;i++){

              scanf("%s",buffer);

              if(!(pp[i]=(char*)malloc(strlen(buffer)+1))){

              print("Out of Memory.\ n");

              exit(-1);

              }

              strcpy(pp[i],buffer);

              printf(pp[i]);

              }

              free(pp);/*all the strings pointed by it are lost!*/

              ………

                  今年以來,原PureAtria公司陸續推出了其系列產品?/FONT>Pure,包括支持內存檢測的Purify ,支持路徑覆蓋的PureCoverage,支持多線程應用程序性能測試的Quantify,以及用以提高測試期間連接編譯被測程序效率的PureLink等。Pure系列現已支持C、C++、FORTRAN語言,以及UNIX和Window NT等操作系統,如Sun OS、Solaris 2.3,HP-UX,Windows NT Server以及IBM A/ X等。

                  結束語

                  充分認識軟件測試的重要性和復雜性,合理地選擇測試方法,有效地組織測試人員和安排測試任務,并且盡量使用軟件測試工具增強軟件測試的自動化程度,無疑可以幫助軟件開發和測試人員大大提高測試效率和軟件的質量。


            七、軟件測試的基本過程

                  軟件測試是一個極為復雜的過程。如圖一所示,一個規范化的軟件測試過程通常須包括以下基本的測試活動。

              ·擬定軟件測試計劃

              ·編制軟件測試大綱

              ·設計和生成測試用例

              ·實施測試

              ·生成軟件問題報告

                  對整個測試過程進行有效的管理實際上,軟件測試過程與整個軟件開發過程基本上是平行進行的。測試計劃早在需求分析階段即應開始制定,其它相關工作,包括測試大綱的制定、測試數據的生成、測試工具的選擇和開發等也應在測試階段之前進行。充分的準備工作可以有效地克服測試的盲目性,縮短測試周期,提高測試效率,并且起到測試文檔與開發文檔互查的作用。

                  此外,軟件測試的實施階段是由一系列的測試周期(Test Cycle)組成的。在每個測試周期中,軟件測試工程師將依據預先編制好的測試大綱和準備好的測試用例,對被測軟件進行完整的測試。測試與糾錯通常是反復交替進行的。當使用專業測試人員時,測試與糾錯甚至是平行進行的,從而壓縮總的開發時間。更重要的是,由于專業測試人員豐富的測試經驗、所采用的系統化的測試方法、全時的投入,特別是獨立于開發人員的思維,使得他們能夠更有效地發現許多單靠開發人員很難發現的錯誤和問題。

                  軟件測試大綱是軟件測試的依據。它明確詳盡地規定了在測試中針對系統的每一項功能或特性所必須完成的基本測試項目和測試完成的標準。無論是自動測試還是手動測試,都必須滿足測試大綱的要求。

                  一般而言,測試用例是指為實施一次測試而向被測系統提供的輸入數據、操作或各種環境設置。測試用例控制著軟件測試的執行過程,它是對測試大綱中每個測試項目的進一步實例化。已有許多著名的論著總結了設計測試用例的各種規則和策略。從工程實踐的角度講有幾條基本準則:

              1.測試用例的代表性:能夠代表各種合理和不合理的、合法的和非法的、邊界和越界的,以及極限的輸入數據、操作和環境設置等;

              2.測試結果的可判定性:即測試執行結果的正確性是可判定的或可評估的;

              3.測試結果的可再現性:即對同樣的測試用例,系統的執行結果應當是相同的。

            八、制定成功的測試計劃


                  “工欲善其事,必先利其器”。專業的測試必須以一個好的測試計劃作為基礎。盡管測試的每一個步驟都是獨立的,但是必定要有一個起到框架結構作用的測試計劃。測試的計劃應該作為測試的起始步驟和重要環節。一個測試計劃應包括:產品基本情況調研、測試需求說明、測試策略和記錄、測試資源配置、計劃表、問題跟蹤報告、測試計劃的評審、結果等等。

                  產品基本情況調研:

                  這部分應包括產品的一些基本情況介紹,例如:產品的運行平臺和應用的領域,產品的特點和主要的功能模塊,產品的特點等。對于大的測試項目,還要包括測試的目的和側重點。

                  具體的要點有:

                  目的:重點描述如何使測試建立在客觀的基礎上,定義測試的策略,測試的配置, 粗略的估計測試大致需要的周期和最終測試報告遞交的時間。

                  變更:說明有可能會導致測試計劃變更的事件。包括測試工具改進了,測試的環境改變了,或者是添加了新的功能。

                  技術結構:可以借助畫圖,將要測試的軟件劃分成幾個組成部分,規劃成一個適用于測試的完整的系統,包括數據是如何存儲的,如何傳遞的(數據流圖),每一個部分的測試是要達到什么樣的目的。每一個部分是怎么實現數據更新的。還有就是常規性的技術要求,比如運行平臺、需要什么樣的數據庫等等。

                  產品規格:就是制造商和產品版本號的說明。

                  測試范圍:簡單的描述如何搭建測試平臺以及測試的潛在的風險。

                  項目信息:說明要測試的項目的相關資料,如:用戶文檔,產品描述,主要功能的舉例說明。

                  測試需求說明:

                  這一部分要列出所有要測試的功能項。凡是沒有出現在這個清單里的功能項都排除在測試的范圍之外。萬一有一天你在一個沒有測試的部分里發現了一個問題,你應該很高興你有這個記錄在案的文檔,可以證明你測了什么沒測什么。具體要點有:

                  功能的測試:理論上是測試是要覆蓋所有的功能項,例如:在數據庫中添加、編輯、刪除記錄等等,這會是一個浩大的工程,但是有利于測試的完整性。

                  設計的測試:對于一些用戶界面、菜單的結構還有窗體的設計是否合理等的測試。

                  整體考慮:這部分測試需求要考慮到數據流從軟件中的一個模塊流到另一個模塊的過程中的正確性。

                  測試的策略和記錄:

                  這是整個測試計劃的重點所在,要描述如何公正客觀地開展測試,要考慮:模塊、功能、整體、系統、版本、壓力、性能、配置和安裝等各個因素的影響。要盡可能的考慮到細節,越詳細越好,并制作測試記錄文檔的模板,為即將開始的測試做準備,測試記錄重要包括的部分具體說明如下:

                  公正性聲明:要對測試的公正性、遵照的標準做一個說明,證明測試是客觀的,整體上,軟件功能要滿足需求,實現正確,和用戶文檔的描述保持一致。

                  測試案例:描述測試案例是什么樣的,采用了什么工具,工具的來源是什么,如何執行的,用了什么樣的數據。測試的記錄中要為將來的回歸測試留有余地,當然,也要考慮同時安裝的別的軟件對正在測試的軟件會造成的影響。

                  特殊考慮:有的時候,針對一些外界環境的影響,要對軟件進行一些特殊方面的測試。

                  經驗判斷:對以往的測試中,經常出現的問題加以考慮。

                  設想:采取一些發散性的思維,往往能幫助你找的測試的新途徑。

                  測試資源配置:

                  項目資源計劃:制定一個項目資源計劃,包含的是每一個階段的任務、所需要的資源,當發生類似到了使用期限或者資源共享的事情的時候,要更新這個計劃。

                  計劃表:

                  測試的計劃表可以做成一個多個項目通用的形式,根據大致的時間估計來制作,操作流程要以軟件測試的常規周期作為參考,也可以是根據什么時候應該測試哪一個模塊來制定。

                  問題跟蹤報告:

                  在測試的計劃階段,我們應該明確如何準備去做一個問題報告以及如何去界定一個問題的性質,問題報告要包括問題的發現者和修改者、問題發生的頻率、用了什么樣的測試案例測出該問題的,以及明確問題產生時的測試環境。

                  問題描述盡可能是定量的,分門別類的列舉,問題有幾種:

              1、嚴重問題:嚴重問題意味著功能不可用,或者是權限限制方面的失誤等等,也可能是某個地方的改變造成了別的地方的問題。

              2、一般問題:功能沒有按設計要求實現或者是一些界面交互的實現不正確。

              3、建議問題:功能運行得不象要求的那么快,或者不符合某些約定俗成的習慣,但不影響系統的性能,界面先是錯誤,格式不對,含義模糊混淆的提示信息等等。

                  測試計劃的評審:

                  又叫測試規范的評審,在測試真正實施開展之前必須要認真負責的檢查一遍,獲得整個測試部門人員的認同,包括部門的負責人的同意和簽字。

                  結果:

                  計劃并不是到這里就結束了,在最后測試結果的評審中,必須要嚴格驗證計劃和實際的執行是不是有偏差,體現在最終報告的內容是否和測試的計劃保持一致,然后,就可以開始著手制作下一個測試計劃了。


            九、報告軟件測試錯誤的規范  
             

                  報告軟件測試錯誤的目的是為了保證修復錯誤的人員可以重復報告的錯誤,從而有利于分析錯誤產生的原因,定位錯誤,然后修正之。因此,報告軟件測試錯誤的基本要求是準確、簡潔、完整、規范。需要掌握的報告技術歸納如下。
               1. 描述 (Descrīption),簡潔、準確,完整,揭示錯誤實質,記錄缺陷或錯誤出現的位置

              描述要準確反映錯誤的本質內容,簡短明了。為了便于在軟件錯誤管理數據庫中尋找制定的測試錯誤,包含錯誤發生時的用戶界面(UI)是個良好的習慣。例如記錄對話框的標題、菜單、按鈕等控件的名稱。

              2. 明確指明錯誤類型:布局、翻譯、功能、雙字節
            根據錯誤的現象,總結判斷錯誤的類型。例如,即布局錯誤、翻譯錯誤、功能錯誤、雙字節錯誤,這是最常見的缺陷或錯誤類型,其他形式的缺陷或錯誤也從屬于其中某種形式。

              3. 短行之間使用自動數字序號,使用相同的字體、字號、行間距

              短行之間使用自動數字序號,使用相同的字體、字號、行間距,可以保證各條記錄格式一致,做到規范專業。

              4. UI要加引號,可以單引號,推薦使用雙引號

              UI加引號,可以容易區分UI與普通文本,便于分辨、定位缺陷或錯誤。

              5. 每一個步驟盡量只記錄一個操作

              保證簡潔、條理井然,容易重復操作步驟。

              6. 確認步驟完整,準確,簡短

              保證快速準確的重復錯誤,“完整”即沒有缺漏,“準確”即步驟正確,“簡短”即沒有多余的步驟。

              7. 根據缺陷或錯誤類型,選擇圖象捕捉的方式

              為了直觀的觀察缺陷或錯誤現象,通常需要附加缺陷或錯誤出現的界面,以位圖的形式作為附件附著在記錄的“附件”部分。為了節省空間,又能真實反映缺陷或錯誤本質,可以捕捉缺陷或錯誤產生時的全屏幕,活動窗口和局部區域。為了迅速定位、修正缺陷或錯誤位置,通常要求附加中英文對照圖。

              8. 附加必要的特殊文檔和個人建議和注解

              如果打開某個特殊的文檔而產生的缺陷或錯誤,則必須附加該文檔,從而可以迅速再現缺陷或錯誤。有時,為了使缺陷或錯誤修正者進一步明確缺陷或錯誤的表現,可以附加個人的修改建議或注解。

              9. 檢查拼寫和語法錯誤

              在提交每條缺陷或錯誤之前,檢查拼寫和語法,確保內容正確,正確的描述錯誤。

              10. 盡量使用業界慣用的表達術語和表達方法

              使用業界慣用的表達術語和表達方法,保證表達準確,體現專業化。

              11. 通用UI要統一、準確

              錯誤報告的UI要與測試的軟件UI保持一致,便于查找定位。

              12. 盡量使用短語和短句,避免復雜句型句式

              軟件錯誤管理數據庫的目的是便于定位錯誤,因此,要求客觀的描述操作步驟,不需要修飾性的詞匯和復雜的句型,增強可讀性。

              13. 每條錯誤報告只包括一個錯誤

              每條錯誤報告只包括一個錯誤,可以使錯誤修正者迅速定位一個錯誤,集中精力每次只修正一個錯誤。校驗者每次只校驗一個錯誤是否已經正確修正。

              以上概括了報告測試錯誤的規范要求,隨著軟件的測試要求不同,測試者經過長期測試,積累了相應的測試經驗,將會逐漸養成良好的專業習慣,不斷補充新的規范書寫要求。此外,經常閱讀、學習高級測試工程師的測試錯誤報告,結合自己以前的測試錯誤報告進行對比和思考,可以不斷提高技巧。 
             
             
            十、軟件測試人員結構組成分析

                  軟件測試工程師是軟件行業中一種即年輕又古老的職業,進入二十一世紀以來,隨著中國加入WTO以后,從事這項職業的人也越來越多。一個公司在組建一個測試隊伍的時候如何分配人員結構,從而使公司軟件測試工作水平得到提高,是大家比較關注的問題。本人依照自己的經驗提出自己的觀點:


            我們首先來看一下測試人員的縱向結構
            1,測試經理
            測試經理主要負責測試隊伍的內部管理以及與其他外部人員,客戶的交流,詳細說來主要包括進度管理,風險管理,資金管理,人力資源管理,交流管理等等,測試經理需要具有項目經理的知識和技能。同時測試工作開始前項目經理需要書寫《測試計劃書》,測試結束需要書寫《測試總結報告》
            2,測試文檔審核師
            測試文檔審核師主要負責前置測試,包括在需求期與設計期間產生的文檔進行審核,比如《業務建模書》,《需求規格說明書》,《概要設計書》,《詳細設計書》等等。審核需要進行書寫審核報告。當文檔確定后,需要整理文檔報告,并且反映介紹給測試設計師。
            3,測試設計師
            測試設計師主要根據需求期與設計期間產生的文檔設計各個測試階段的測試用例。
            (往往測試文檔審核師,測試設計師可以有相同的一組人來完成)
            4, 測試工程師
            測試工程師按照測試用例,來完成測試工作。


            但是測試人員應該有哪些人來組成呢?也就是測試人員的橫向組成,讓我們再來討論討論:
            1, 需要具有一定開發經驗的計算機專業人員
            由于具有一定開發經驗的計算機專業人員即懂得計算機的基本理論,又有一定的開發經驗。所以對于軟件中哪里容易出錯,哪里不容易出錯他們了如指掌;他們可以分析程序的性能,軟件性能差是否是占有內存空間太多,或者是占有CPU時間太多引起的,還是其他原因,他們往往是專家。尤其是進行非功能測試的時候,他們可以更好的搭建系統測試平臺。這種人員應該占測試隊伍中一半以上。
            2, 需要具有本軟件業務經驗的人員
            測試隊伍中需要有這樣的人員的目的在于,這些人員由于對業務非常熟悉,軟件質量的前提又是滿足用戶的需求。專業業務知識是計算機專業人員達不到的,所以這方面人才可以利用它們的業務知識和專業水平,參與系統需求期間的文當審核,可以發現軟件中存在的業務性錯誤。比如專業用語不準確,業務流程不規范等等,這種人才對于專業性比較強的軟件測試工作尤為重要,比如稅務,法律,藝術,CAD,CAM
            3, 只需要會操作計算機的人員
            由于軟件一旦賣出去之后,使用軟件的人各種各樣,各種各樣的人帶來各種各樣的操作情況,請一大部分人員在軟件測試工作后期進行測試工作是十分重要的,他們往往會發現專業測試人員測試不出的東西和一些希奇古怪的錯誤。這就是軟件測試學中所謂的猴子測試法。
            對于一個軟件公司來說,并不是說所有的測試隊伍都需要這三種人員,實際中可以一組人代替多個角色,但是要遵循以下原則:
            1,對于業務不是很專業的軟件,具有一定開發經驗的計算機專業人員與具有本軟件業務經驗的人員可以合并;
            2,只需要會操作計算機的人員,可以由公司行政人員來充當。

            十一、軟件測試的現實和理想
             
             
              “從我在微軟工作的經歷來看,軟件測試絕對不是開發活動完成后的收尾工作,很多大型的開發項目,測試會占據項目周期一半以上的時間。以IE4.0為例,代碼開發時間為6個月,而穩定程序花去了8個月的時間。”前微軟亞洲研究院博士、軟件測試專家陳宏剛談道。從投入的資金和人力物力來看,測試、使產品穩定和修改花去的時間可能占到80%。
            還處在嬰兒期

              軟件測試之所以發展相對緩慢,一個原因是做研究和做開發的人交流的機會相對少。只有做大型系統工程的人才會對測試提出較高的要求,重要性才能顯現出來,而做研究和教學的人沒有大型系統工程案例,所以造成了測試理論研究的發展缺乏充實的基礎材料。真正做大型系統開發的工程師,又沒有時間將第一手的測試經驗變成系統的理論。

              “在美國,佛羅里達州和華盛頓州分別有一所大學開設軟件測試課程,其他有正規課程的學校不是很多。軟件測試正停留在沒有學科系統、沒有系統教育的階段。雖然已經有學校開設了這門課程,但是使用的教學案例,多半是單機軟件,還談不上系統的理論。”陳宏剛博士介紹說。

              高素質的“雜牌軍”

              由于企業對測試人才有著迫切的需要,因此,只好自己培養測試人才隊伍。例如微軟公司,對不同的產品制定測試規范,開設一些課程,通過講座的形式對測試技術人員進行培訓,但是也還未形成系統的理論。

              即使在微軟,測試隊伍是典型的“雜牌軍”,沒有科班,沒有統一的專業,更多的是具有豐富的經驗和不同行業背景的員工,例如具有語言學、數學、物理學、計算機、工程、管理等學科等背景的員工。但是,這不是說隨便什么人都可以做測試工作,陳宏剛工作過的那個試驗室,20個人中有7個博士。可見,雖然測試不是一個專門的學科,但是,這個部門對于一個成熟的軟件企業又是至關重要的部門。

              認識需再提高

              IBM和微軟公司屬于領先的大公司,對測試的認識也經歷了一個過程。開始的時候,也是開發人員兼職做測試,就像今天國內一些較小規模的軟件企業。但是,后來的結果表明,花在軟件修補上面的費用太高,以至于遠遠超出了所能夠允許的范圍。這個時候,增加測試隊伍的規模,提高測試隊伍的素質,提高測試隊伍的待遇和受重視的程度是更加劃算的。

              還有一個問題是,很多工程師不愿意做測試,認為是一種打下手的工作,沒有前途,這也是國內比較大軟件企業面臨的問題。所以,企業從上到下普遍自覺和不自覺地只重視技術,不重視質量,后果是產品在市場上競爭力不高,產品售后維護和服務費用偏高。

              巨大反差

              微軟的開發工程師與測試工程師的比例是1∶2,國內一般公司是6∶1。而且,致命的問題是沒有哪個機構專門培養測試工程師。這個矛盾提示我們,在中國不能等到實際的需求和人力資源矛盾十分尖銳的時候,再談培養問題;也不能等到產品質量成為產業阻礙的時候再來提高軟件業的測試水平。測試工作不能靠手工勞動來完成,更多的情況是要使用工具軟件和編寫測試程序來完成,培養全面的測試專業人才是項任重道遠的工作。

            十二、軟件測試的新模型   

                  通常情況下,一個軟件模型說明的內容主要包括,在測試過程中你應該考慮到哪些問題,如何對測試進行計劃,測試要達到什么目標,什么時候開始,在測試中你要用到哪些信息資源。一個好的模型可以引導你對問題進行思考,而不好的模型則只能使你誤入歧途。

                  這里我要宣稱的是,目前的大多數軟件測試模型都是不好的模型。這是因為這些測試模型僅僅是軟件開發模型的一些裝飾和補充而已。

                  人們一直在苦苦尋找軟件開發的模型,在創建了新的模型后,就把測試作為一個階段放在模型的后面部分。因此測試總被作為一種事后行為,測試總是被開發所驅動。總的來說,我們是在檢測他們的完成品。但是,作為事后處理的測試,其驅動方式是不正確的。實際上它顯而易見地和開發過程中各種行為之間有關,測試沒有起到應有的平衡作用。這樣的測試只是檢測了開發人員做了什么,而并沒有檢測到他們是否按照規則做了什么,這樣的做法割裂了本該緊密聯系的行為,剩下的只有那些匆忙而草率的想法所帶來的傷害。

                  而這樣做的結果就是效果很差的、效率很低的測試。效果很差的測試將導致很多bug沒有被發現,而效率很低的測試所浪費的是成本。

                  在本文中,我要做2件事,其一,我要否定一個不好的模型,即V模型。我希望通過論述來表明,“單元測試”和“集成測試”這2個詞匯可以從我們的詞匯表中取消了。其二,我將描述一個更好的模型。不過首先我認為,要真正擁有一個充分合理的模型還為時尚早。我僅僅是描述了一些新模型應該符合的重要的要求。這些要求將在本文末尾處列舉。

                  V模型有什么問題呢?

                  在本文中我要把V模型作為不好的模型的典型來進行分析。我選擇V模型作為分析的典型是因為V模型是最廣為人知的測試模型。

                  最典型的V模型版本一般會在其開始部分對軟件開發過程進行描述,如下圖所示:

             

              (圖1--V模型的各級開發階段)

                  這是古老的瀑布模型。作為開發模型,它有很多問題,不過這里不作討論。盡管它的各種狀態是我們接著要討論的大家最熟悉的V模型的基礎。我的批評意見同時也針對其它的裝飾在一些更好的開發模型之上的測試模型,例如螺旋模型[Boehm88]。

                 在V模型中,測試過程被加在開發過程的后半部分,如下圖所示:

             

              (圖2--V模型示意圖)

                  單元測試所檢測的是,代碼的開發是否符合詳細設計的要求。集成測試所檢測的是,此前測試過的各組成部分是否能完好地結合到一起。系統測試所檢測的是,已集成在一起的產品是否符合系統規格說明書的要求。而驗收測試則檢測產品是否符合最終用戶的需求。

                 對于測試設計,顯而易見的是,V模型的用戶往往會把執行測試與測試設計分開對待。在開發文檔準備就緒后,就可以開始進行相關的測試設計。如下圖所示,相應的測試設計覆蓋在了相關的開發過程之上:

             

              (圖3--將測試設計覆蓋了開發過程后的V模型)

                  V模型有著很吸引人的對稱外形,并且把很多人都帶入了歧途。本文將集中討論它在單元測試和集成測試中引起的問題。

                  為了說明的方便,這里專門制作了以下圖片,圖中包括一個單獨的單元,以及一個單元組,我稱之為子系統(subsystem)。

             

              (圖4--一個假想的子系統)

                  對于一個單元應該多大才最為合適的問題,已經有過很多的討論,究竟一個單元僅僅是一個函數,一個類,還是相關的類的集合?這些討論并不影響我在這里所要闡述的觀點。我們權且認為一個單元就是一個具有最小程度的代碼塊,開發人員可以對進行獨立地討論。

                 V模型認為人們首先應該對每一個單元進行測試。當子系統中所有的單元都已經測試完畢,它們將被集中到一起進行測試,以驗證它們是否可以構成一個可運行的整體。

                  那么,如何針對單元進行測試呢?我們會查看在詳細設計中對接口的定義,或者查看源代碼,或者同時對兩者進行查看,找出符合某些測試設計中的有關準則的輸入數據來進行輸入,然后檢查結果,看其是否正確。由于各單元一般來說不能獨立地運行,所以我們不得不另外設計樁模塊(Stub)和驅動模塊(Driver),如下圖所示。

             

              (圖5:單元及其外部的驅動模塊和樁模塊)

                  圖中的箭頭代表了測試的執行軌跡。這就是大多數人所說的“單元測試”。我認為這樣的方法有時候是一種不好的方法。

                  同樣的輸入也可以有同一子系統中的其它單元來提供,這樣,其它的單元既扮演了樁模塊,又扮演了驅動模塊。如下圖所示:

             

              (圖6--子系統內部各單元間的測試執行軌跡)

                  到底選擇哪一種方法,這需要一種折衷和權衡。設計樁模塊和驅動模塊要付出多少代價?這些模塊如何進行維護?子系統是否會由此而掩蓋了一些故障?在整個子系統范圍內進行排錯的困難程度有多大?如果我們的測試直到集成測試時才真正開始,那么一些bug可能較晚才被發現。由此造成的代價同設計樁模塊和驅動模塊的代價如何比較?等等。

                 V模型沒有去考慮這些問題,當單元開發完成后就執行單元測試,而當自系統被集中在一起后就執行集成測試,僅此而已。令我奇怪和沮喪的是,人們從不去做一些權衡,他們已經受制于他們的模型。

                  因此,一個有用的模型應該允許測試人員考慮節省并推遲測試的可能性。

                  一個測試,如果要發現一個特定的單元中的bug,最好是在該單元保持獨立的情況下執行,并且在其外部輔以特定的樁模塊和驅動模塊。而另一種方法則是讓它作為子系統的一部分來進行測試,該測試的設計主要是為了發現集成的問題。由于一個子系統本身也需要樁模塊和驅動模塊來模擬該子系統和其它子系統的聯系,因此,單元測試和集成測試可能被推遲到至少整個系統已經部分集成的時候。在這種情況下,測試者可能通過產品的外部接口同時進行單元測試、集成測試和系統測試,同樣的,其主要目的還是為了減少總體生命周期的成本,對測試成本和延期進行測試及由此造成延期發現bug的代價成本進行權衡。據此而言,“單元測試”、“集成測試”和“系統測試”的區別已經大大削弱了。其結果可參考下圖:

             

              (圖7--新的方法:在部分階段延遲進行單元測試和集成測試)

                  在上圖右邊的方塊中,最好要改成為“執行某些適當的測試并得到相應的結果”。

                 圖中的左邊會怎樣?考慮一下系統測試設計,它的主要根據和信息來源是是規格說明。假設你知道有2個單元處在一個特定的子系統中,它們在運行時相互聯系,并且要執行規格說明中的一個特定的聲明。為什么不在該子系統被集成時立即對此規格說明中的聲明進行測試,就象是在設計完成后立即開始測試的設計一樣呢?如果該聲明的執行和子系統外的子系統沒有任何關系,為什么還要等到整個系統完成以后再測試呢?難道越早發現bug成本越低不對嗎?

                 在上一張圖片中,我們用了向上指的箭頭(更有效,但在時間上有延遲)。這里還可以把箭頭往下指(在時間上提前):

             

              (圖8--新的方法:在不同階段上提前進行測試設計)

                 在這種情況下,左邊的方塊中最好被標記為:“在當前信息條件和情況下可以做的任何測試設計”。這樣,當測試設計得自于系統中某一個組件的描述時,模型必須允許這樣的測試在組件被裝配之前被執行。我必須承認我的圖片非常難看,這些箭頭指得到處都是,對此我有2點說明:

              1. 我們所討論的事情不是創造美,而是想要發現盡可能多的嚴重錯誤,同時盡可能地降低成本。

              2. 難看的部分原因也是因為必須按照某些次序來執行的結果,亦即開發人員先提供系統描述文檔,然后測試和這些文檔進行關聯。這些文檔就象是堅實的老橡樹,而測試設計則象是細細的枝條纏繞在樹上。如果我們采用不同的原理來進行組織,圖片可能就會變得好看些。但復雜性仍不可避免,因為我們要討論的問題本身就很復雜。

                  V模型失敗的原因是它把系統開發過程劃分為具有固定邊界的不同階段,這使得人們很難跨過這些邊界來采集測試所需要的信息。有些測試應該執行得更早些,有些測試則需要延后進行。而且,它也阻礙了你從系統描述的不同階段中取得信息進行綜合。例如,某些組織有時執行這樣的做法,即對完成的工作進行簽署。這樣的規定也擴展到系統測試的設計。簽署表示已經過評估,該測試設計工作已經完成,除非對應的設計文檔改變,否則就不會被修訂。如果同這些測試相關的信息后來被重新挖掘和認識,例如,架構設計表明有些測試是多余的,或者,詳細設計表明有一個內部的邊界可以和已存在的系統測試組合在一起進行測試的話,那么實際上還需要繼續調整原來的系統測試設計。

                  因此,模型必須允許利用不同來源的綜合信息進行個別的測試設計。另外,模型還應該允許在新的信息來源出現后重新進行測試的設計。

                 一個不同的模型

                 讓我們來看本文的第二項內容,一個不同的模型。

                 很多時候人們把代碼移交給其他人,并且說:“希望你能接受和喜歡它。”這不僅發生在將整個項目放在一張光盤中交給客戶的時候,也發生在項目內部。

                 例如,一個小組對另一個小組說:“我們已經完成了為COMM庫加入了對XML的支持。源代碼現在已經放在master庫中,可執行庫則已經加入到集成與創建的環境中。XARG小組的工作已經沒有什么阻礙了,隨時去取吧。”

                  某個程序員檢查了bug的修改并且發出郵件:“我已經修改了Bug列表中的那個Bug,很抱歉!”至此,早先受該問題影響的其它代碼就可以繼續處理了。

                 在這些情況下,人們要把代碼移交給其它人,其中有可能會存在一些影響。測試人員需要干預這個過程。在移交之前,測試人員應執行這些代碼,發現其中的bug(影響),并且提出問題:“你確實要提交這些嗎?”由此,移交的內容可能會被延期,直到bug被修復好。

                  盡管你還要做其它的各種測試,這項測試仍然是很基本的測試工作。如果你沒有做這樣的測試,就不能算是合格的測試人員。

                  我們的測試模型必須包含這一重要的現實需要:針對代碼移交的測試。由此,測試模型應提示進行針對每一次代碼移交的測試。

                  就讓我以支持XML的COMM庫作為例子。這里存在著一個小組把代碼移交給XARG小組以進行項目的余下部分。那么誰會遭受影響?

                  要將這些支持XML的代碼直接進行使用的XARG小組可能會立即受到影響;

                  這可能會在稍后影響到市場人員,他們要在一個行業展示會議上為“合作伙伴發行”版本提供產品演示和宣傳,而XML支持是影響他們銷售的重要部分;

                  還有,它可能損害采納我們的產品的合作伙伴。

                  現在我們可以提出一些有趣的關于測試計劃的問題了。最簡單的可以做的事情是,在移交的時候立即執行XML支持的完整測試。(“完整”的含義是,為此設計盡可能多的測試)但也許一些XML特性并不是XARG小組所需要的,因此可以把它們放在合作伙伴版本封版(下圖中的“Partner Release”)的測試中去。這意味著可以把一些XML相關測試放到稍后的移交過程中去。或者基于其它理由,例如在近階段有其它的測試任務要執行。而XARG小組則要因XML中的bug修復而延遲一小段時間。

                  我們的測試計劃所表示的進度可以通過在開發的時間線上進行注解的方式來表現,如下圖所示:

             

              (圖9:添加在開發計劃之上的測試計劃)

                  我們應嚴格地圍繞在XML支持的功能交接的時段里進行測試。測試設計和測試支持工作要早于測試執行。而另外的XML測試則要延遲到基于整個項目范圍的“代碼完成”(圖中的“Code Complete”里程碑),或者要等到全部的子系統被集中在一起,而且整個產品為了行業會議而在經過穩定化處理后創建了版本(圖中的“Partner Release”里程碑)。

                  顯然,有兩項內容沒有包含在代碼完成里程碑中:

                  還有大量其它的測試工作(包括設計、工具選用)。這些工作可能因為COMM以外的子系統的交接而延期。

                  而且,還有用于完成里程碑中所規定的某些風險的測試,例如,可能還有一組用于運行市場人員的演示Demo腳本的測試,包括她可能在無意中引起的偏離。其目的是要避免這樣的情況,即當她站在1000人的觀眾面前時,她還僅僅是第一次以某種特定的順序來輸入數據。

                  一些首次交接時進行的XML測試需要在代碼完成里程碑上再次執行。

                  我的觀點是,測試計劃是由很多困難的決定所組成,這些決定包括人員組織安排、機器資源配置、測試設計的時間定位、測試支持代碼的數量、哪些測試要做自動化,等等。這些決定應根據單獨的交接中的內容信息來作出。如果僅有一次交接,那么你可以更順利一些。測試計劃還應繼續考慮以下問題:

              1. 風險分析,誰會因此受到損害,以什么方式?

              2. 選定一種測試途徑來定位特定的風險。

              3. 對測試設計和執行的周期和成本進行估計。

              4. 在項目進度上的特定位置,將計劃納入執行的行動:

              A. 開始對測試進行設計…

              B. … 同時設計和創建一些支持測試的代碼…

              C. … 在全部測試完成以前就執行部分的測試,因為可能存在不只一次的交接,在每一次交接的測試規劃中,可能存在一些潛在的復雜的相互影響。工作安排不得不進行一些調整以達到相互間的平衡。測試支持代碼和工具需要在各項任務中得到共享。你還必須考慮到在什么程度上讓那些為早先的交接所設計的測試在以后重新執行,等等。

                  這看起來很復雜。看上去似乎有太多的內容需要跟蹤,而且太多的內容可能被忽略。也許你認為我是在要求你要對每一次交接來執行IEEE 829 [IEEE98]中關于測試計劃的要求,然后把它們合并為一份貫穿整個項目的針對交接進行測試的測試計劃。

                  是,也不是。思考問題總是要占用時間的。太多的計劃可能會減少結果的產出。在有些時候,你需要做的是停止計劃并開始行動。例如,你無法思考并描述每一個bug修復,盡管bug修復也是一種交接。

                  但是bug修復是實際工作中現實存在的問題。總體項目計劃中應該包含bug修復。需要強調的是,你應該有一個默認的bug修改處理的標準過程,該過程應包括運行于每一個提交的bug修復的驗證過程。你還需要努力地去思考問題。很多時候,各項驗證是被放在一起同時進行并完成的。

                  比較現實地來說,一個模型應該允許一些機械式行為,例如,“不管是哪一個X類型的交接,都要執行下列操作”。同時我們鼓勵對特定的交接執行剛剛夠的檢查,對于風險越小的交接,就越可以采用機械式的測試行為。

                  一個明確考慮到基本的測試現實的模型肯定會比忽略這些現實或者把你的工作復雜性完全抽象化的模型做得更好。文檔則是另一個例子。

                  我還沒有提到需求及規格說明書,或者設計文檔。某個交接中產生的一系列變化會引起很多爭議。這些文檔所扮演的角色是什么呢?它們常常是這么被使用的:

             

              (圖10:測試中對開發文檔的利用)

                  文檔可以指導你在一個交接變化時如何作出反應。如果你有一份很好的需求文檔,它可能是產品所解決的問題的描述,盡管也許不是很直接。它可以幫助你對風險進行分析。一份好的規格說明應對系統的行為進行描述。這將幫助你把測試方法轉化為具體的測試。一份好的架構設計則可以幫助你理解變化可能引起的幾種不同的情況:系統的其它部分會受到怎樣的影響?什么測試需要再次進行?

                  我并不是經常能看到好的文檔。需求文檔常常象是市場銷售用的系統特性列表。規格說明書有時就象是在代碼完成后提交的用戶手冊文件。而設計文檔經常不存在。

                  好了,通過針對交接所引起的變化的集中討論,我已把測試過程和軟件開發過程相對地分離開了。如果文檔中關于“XML支持功能加入到COMM”的描述很薄弱的話,我會盡自己所知來進行盡可能好的測試設計。然后,假如在項目后期,XML相關的用戶文檔出來了,我就可以對后來再次提交的交接增加相關的測試。假如市場需求改變了,她們經常會這么做,我還會在此后增加或者去除一些測試。所有這一切看起來是這樣的:

             

              (圖11--在文檔不完整的條件下進行測試,并在后期補充測試)

                  這樣,雖然項目文檔總是不到位,而且經常延遲提交,測試的效果也因此常常被降低,我們還是要避免測試受到項目文檔的制約。

                  頭腦靈活的測試人員并不過于相信文檔。畢竟,總是人在犯錯誤。那么,難道不是人在寫這些文檔嗎?

                  由于“正式的”文檔是很薄弱的,測試模型必須明確地鼓勵在測試過程中使用項目文檔之外的各種不同信息來源。

                  測試人員必須和程序員、用戶、市場人員、技術作者以及任何的可能為實現更好測試提供線索的人進行交流。測試人員還應該努力把自己沉浸在某些技術所構建的氛圍中。例如,我希望測試人員在做XML測試工作時常去訪問W3組織的XML地址(http://www.w3.org/XML/)以及其它XML站點、郵件列表,甚至包括比較特別的 如Dave Winer的DaveNet/腳本新聞(http://www.scrīpting.com/)。這些資源并不是所謂的“輔助通道”,而是可以被列入計劃和進度日程的資源。

                  另外,所執行的測試本身也是一種有用的信息的資源。好的測試人員會仔細閱讀bug報告,因為這些報告講授了系統所存在的薄弱之處。特別地,這些報告還暗示了一些正式的架構設計所沒有提供的架構上的策略。執行測試的行為應該產生一些新的測試想法。如果模型沒有考慮到這些,那么它就是一個落后的模型。

                  因此,測試模型應該包含反饋的循環,讓測試設計可以考慮到,在運行測試時還可以繼續發現到更多的測試內容。

                  在我們的工作中,真正的復雜性來自于所有計劃的執行都處于一個不確定的、容易忽略的環境里。代碼并不是唯一在不斷變化的東西。而計劃日程也在改變。新的功能擴充會帶來新的里程碑。某些功能會從當前版本中去除。在開發過程中,所有人--市場人員、開發人員和測試人員,都會逐漸對諸如“產品究竟提供什么”這樣的問題有越來越清晰的了解。在這些情形下,我們怎么能說測試計劃的第一個版本會是完全正確的呢?

                  因此,模型應該要求測試計劃人制定明確的規定,對已交接的交接內容,新的交接,以及交接內容的變更進行負責。

                  總結

                  V模型有以下致命的缺陷,其它模型實際上也與此相似:

              1. 忽略了這樣的事實情況,即軟件開發是由一系列的交接所組成,每一次交接內容都改變了前一次交接的行為。

              2. 依賴于開發文檔的存在,及文檔的精確性、完整性,并且沒有對時間進行限制。

              3. 認定一種測試的設計是依據某一個單獨的文檔,而不包括根據其前后階段的文檔的修改而作相應修改。

              4. 認定這些依賴于某個單獨文檔的測試一定要在一起執行。

                  我大致描述了一個替代模型,但還不夠精細。它考慮到了代碼的交接和里程碑。對測試成本控制作了以下明確描述:

                  測試設計的目標是定義好可能發現bug的測試輸入,而測試執行的目標是以各種方式加入這些數據,并檢驗結果,由此來降低整個生命周期的成本。

                  我們的模型假設軟件產品總是不完美的,開發過程中有很多變更,而且對產品的測試也是一個不斷學習的過程。

                  過去,我很少考慮到模型。表面上我一直還在用V模型。雖然我按此制訂計劃,但我總是還要花費很多額外的精力和時間來考慮模型中沒有提到的方面。換言之,模型造成了一些阻礙,因此我有必要對此進行研究。

                  對一個新的模型來說,對模型所提出的要求必須非常明確,這就象業務需求對產品開發非常重要一樣。我希望自己對本文中所提倡的模型的要求的描述能夠和V模型中的描述一樣精確,并具有同樣的指導意義。

                  理想的測試模型應該包括下列要求:

              1. 使測試對項目中的每一次代碼交接有所反應。

              2. 要求測試計劃人制定明確的規定,對已交接的交接內容,新的交接,以及交接內容的變更進行負責。

              3. 在測試設計中,除了使用項目文檔外,還應明確鼓勵使用其它各種信息,這些信息有不同來源。

              4. 事實上項目文檔總是不到位,而且經常延遲提交,測試的效果也因此常常被降低。但我們還是要盡量避免測試受到項目文檔的制約。

              5. 允許根據多種來源提供的綜合信息來設計一些獨立的測試。

              6. 讓測試被重新設計,以新的信息形式進行表現。

              7. 包含反饋的循環,讓測試設計可以考慮到,在運行測試時還可以繼續發現到更多的測試內容。

              8. 讓測試人員認識到,避免測試的延遲可以節省成本。

              9. 在組件被組裝到程序中去之前對組件的執行進行測試。

            posted @ 2008-07-15 18:41 Niino 閱讀(418) | 評論 (0)編輯 收藏

            C++編程風格指南

            posted @ 2008-07-12 11:08 Niino 閱讀(117) | 評論 (0)編輯 收藏

            有一個農夫決定買一匹騾子,他認為這個騾子至少得能扛動3袋大米,他才會決定買這匹騾子(用戶提出的性能需求)。

            他來到農貿集市上,試了好幾頭騾子,都不合適,最后終于有一頭騾子能夠比較輕松的扛動這3袋大米,而且還瀟灑的走了幾步(性能測試通過)。

            農夫想看看這頭騾子到底能拉多少大米,于是一袋袋的往騾子身上加,加到第7袋的時候,騾子雙腿打顫,賣騾子的心疼起來,立刻制止,農夫滿意的買下了這頭騾子。(容量測試通過)

            農夫高高興興地牽著這頭騾子回家,而且給它扛了4袋大米(系統超負荷運行),因為他跑了太遠才買到了這匹不可多得的騾子,他想看看它到底能有多強,所以農夫決定,讓這匹騾子就扛著這四袋大米走回家試試看.(在超負荷情況下檢驗系統能正常運行多久,進入壓力測試)

            這匹騾子真的很厲害,剛開始的時候還一顛一跑的,可是家離集市有5公里,騾子越馱越費勁。快到家的時候,已經是走兩步歇一步了。終于到家了。(壓力測試通過)

            農夫非常自豪地叫出自己的老婆,說:“老婆子,快來看看,看我買到了一頭多么厲害的騾子啊!”,老婆出來后,農夫把他和騾子在一路上的經歷都告訴了老太婆,誰知這個老太婆卻說:“你真蠢,這么大老遠的路,也不讓騾子馱著你,竟然和這頭傻騾子一樣走回來!”,農夫聽了,覺得非常后悔,說:“那好吧,既然在路上它沒有馱我,那就讓它現在補上,也算是對我的補償。”,騾子還沒有反應過來,就看那老農夫一個箭步,跳到了騾子背上(這相當于容量測試的極限點),可憐的騾子,無論如何也不會想到,這狠心的農夫竟然在它走了這么久之后,不但沒有幫它卸掉身上的重擔,更沒有給它喝口水,竟然變本加厲的跳到了它那本已彎曲的背上。可憐的騾子啊,就這么一命嗚乎了!就看見那個騾子、農夫和4袋麥子一起轟然倒地。(相當于已經到了系統的最大拐點,造成了系統癱瘓,無法使用)。

            posted @ 2008-07-10 15:00 Niino 閱讀(142) | 評論 (0)編輯 收藏

             

            當一個測試人員證實了程序里充滿bug的時候,他是一個好的還是一個糟糕的測試人員呢?在某些開發人員看來,這是一份糟糕的工作。看上去荒謬可笑,因為項目經理等人會因產品的延期交付而責備測試人員,而且開發人員會抱怨(通常是以玩笑的形式):“測試人員對于程序過于較真。”因此很明顯的,還有比計bug數更好的測試方法。這里是一些測試人員如何應對開發人員的小竅門。

            當我作為一個測試人員開始我的工作時,我意識到在開發人員和測試人員之間存在一種持久的對抗關系,而且我毫不費力的相信了:這太常見了!我接受開發人員不歡迎的態度,因此我認為所有的測試人員在他們工作的不同時刻都會有相同的經歷。從冷漠的不屑一顧到坦白的敵對相視(有時掩飾以同情的微笑),一個測試人員不得不忍受開發人員很多。這樣很難保持測試人員積極的態度。但我們測試人員積極的態度取決于我們保持的優先權和保證項目質量的責任。我從Cem Kaner的《計算機軟件測試》一書中摘得一句優美的話:“最好的測試人員不是發現了最多個bug或者使最多的開發人員感到不安的那個人,而是使開發人員fix最多bug的那個測試人員。”那么,我們從中能得到什么樣的啟發呢?

            態度誠懇,有耐心。

            作為一個測試人員,你也許發現說服一個開發人員修改你發現的缺陷比你發現缺陷本身更難。通常情況是,測試人員發現一個bug,開發人員會準備好十個理由來反駁。對于開發人員而言。有時很難接受自己的代碼有缺陷這一事實——即便是另外一些人已經查明確實如此。開發人員需要測試團隊的支持,他們能說服開發人員發現一個新的bug,對于盡可能使產品達到最好這一目的,是想望的、具有建設性的并且是非常重要的。采用一種人性化的方式,將更有利于測試人員了解開發人員。相信我,沒有這樣的一個人會和你坐在一起嘲笑他自己引出的bug。誠懇地態度常使開發人員說:“是嗎?多虧你的bug報告,我得到一個非常重要的進步!”

            要善用交際手段。

            試著機智圓滑的展示你發現的bug并不帶任何抱怨的解釋它:“我肯定這是一個很小的bug,你會馬上解決掉它。這是迄今為止非常完美的程序。”開發人員會非常歡迎解決它。

            要善于采取心理戰術,

            時不時地贊美開發人員的工作。大多數開發人員不喜歡我們的bug報告的原因很簡單:他們認為我們破壞了他們的辛勤勞動的成果。一些測試人員在只有發現問題的時候才與開發人員交流。對于開發人員而言,軟件就像自己的孩子,而你測試人員只是一個外來的干預者。我告訴我的開發人員因為他們我才能留在公司,并且因為我,他們工作上的失誤才能得以補救。這是在開發人員和測試人員之間的一種具有象征意義并且非常有益的關系。

            不要使開發人員不安。

            沒有人喜歡別人指出自己的錯誤,這是人的本性。試著解釋fix某個bug的具體辦法,譬如需要一個大的圖片,遠比自顧自的提一大堆bug報告好的多。一大堆的缺陷報告不僅不能使開發人員著急,還會使你的辛苦工作在他們看來毫無用處。就像測試人員不能對程序測試完全一樣,開發人員也不可能設計出沒有錯誤的程序。他們比需要其他事情更強烈的需要測試人員的理解。我們期望出現錯誤,因為他們是整個過程的一部分。

            有得必有失

            我知道測試人員盡可能的將bug報告提的很嚴格。他們甚至不去聽取開發人員關于這個bug不能fix或者是為了實現某個特性的解釋。試著讓自己放松下來,坐下來和開發人員一道分析這個bug的優先級和嚴重程度,如果這個開發人員對于不樂意修改這個bug有合理的和明智的解釋的話,試著去理解他。只是要確保哪里是保證產品質量的底線。

            警惕心理

            外交手段和彈性應對并不能替換必需的警惕心理。開發人員經常找理由解釋他們拒絕fix一個bug時,說因為他們沒有意識到(或者你沒有告訴他們)這個問題有多嚴重。設計你的bug報告和測試文檔,使其能清楚地顯示出問題的風險和嚴重程度。甚至更好的辦法是召開一次會議,向開發人員解釋這個bug。一個聰明的測試人員是一個在聆聽與表達之間取得一個平衡的人。如果一個開發人員不能說服你不fix一個bug時,說服他fix這個bug就是你義不容辭的責任了。


            轉自 http://www.51testing.com/?59943/action_viewspace_itemid_86925.html
            posted @ 2008-07-10 11:12 Niino 閱讀(220) | 評論 (0)編輯 收藏
            僅列出標題
            共3頁: 1 2 3 
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            久久婷婷五月综合国产尤物app | 久久伊人五月丁香狠狠色| 97久久精品午夜一区二区| 久久香蕉综合色一综合色88| 久久996热精品xxxx| 少妇人妻综合久久中文字幕| 久久国产高清字幕中文| 久久乐国产综合亚洲精品| 久久国产精品久久久| 麻豆精品久久久久久久99蜜桃| 9久久9久久精品| 精品久久综合1区2区3区激情 | 亚洲国产精品久久久久网站 | 久久93精品国产91久久综合| 日产精品久久久久久久| 久久婷婷国产麻豆91天堂| 久久天天躁狠狠躁夜夜avapp| 久久国产一片免费观看| 日日躁夜夜躁狠狠久久AV| 亚洲国产精品嫩草影院久久| 久久免费高清视频| 狠狠色丁香久久婷婷综合五月| 亚洲国产成人精品无码久久久久久综合| 久久久久免费看成人影片| 老司机午夜网站国内精品久久久久久久久 | 欧美国产精品久久高清| 2022年国产精品久久久久| 亚洲乱码中文字幕久久孕妇黑人| 久久久这里有精品中文字幕| 久久精品国产亚洲77777| 国产成人精品三上悠亚久久| 亚洲欧美日韩精品久久亚洲区 | 国产一区二区久久久| 久久精品中文字幕有码| 久久精品国产精品亚洲艾草网美妙| 2020最新久久久视精品爱| 久久久久久久人妻无码中文字幕爆| 久久99精品国产自在现线小黄鸭| 潮喷大喷水系列无码久久精品| 99久久99久久久精品齐齐 | 日韩美女18网站久久精品|