軟件測試Correct邊界條件_第1頁
軟件測試Correct邊界條件_第2頁
軟件測試Correct邊界條件_第3頁
軟件測試Correct邊界條件_第4頁
軟件測試Correct邊界條件_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Correct邊界條件代碼中的許多Bug都出現(xiàn)在“邊界條件”附近,也就是說,在那些條件下,代碼的行為可能不同于平常的、每天都能運行到的程序路徑。例如,假設你有個接收兩個整數(shù)的函數(shù):public int calculate( int a, int b)return a/(a+b);大多數(shù)時候,代碼會返回你所期望的值。但是如果a和b的總和正好為零,則將會得到 ArithMeticException異常,而不是期望的返回值。這就是邊界條件一在這種條件下代碼可能 會突然出錯,至少不像你所期望的那樣運行。我們用首字母縮略詞CORRECT來幫助你考慮要如何測試哪些邊界條件。一致性(Conformanee)

2、值是否符合預期的格式 ?有序性(Ordering)一組值是該有序的,還是該無序的?區(qū)間性(Range)值是否在一個合理的最大值和最小值的范圍引用,耦合性(Reference)代碼是否引用了一些不受代碼本身直接控制的外部因素?存在性(Existence)值是否存在(例如,非null,非零,包含于某個集合等 )?基數(shù)性(Cardinality)是否恰好有足夠的值 ?時間性,絕對的或者相對的(Time)所有事情是否都是按順序發(fā)生的?是否在正確的時間?是否及時?下面讓我們按順序逐一來查看這些邊界條件。請記住,在考慮上面的每一個方面時,你都需要同時考慮傳入方法作為實參的數(shù)據(jù)和由方法或者類所維護的內部數(shù)據(jù)

3、。你需要好好回答的根本問題就是:還有什么會出錯一旦你想到有什么可能會出錯,就寫一個針對它的測試。當測試通過之后,再問自己“還有什么會出錯?”然后再寫一個測試,如此往復。5.1 一致性很多時候,你所期望的或產生的數(shù)據(jù)必須符合某種特定的格式。比如一個e-mail地址并不僅僅是一個簡單的字符串。你期望e-mail地址是這樣的格式:n ame可能還會有一些附加的用點(.)隔開的部分:first name.last namesubdomai 甚至還有如下更為少見的格式first name .l ast name%somewheresubdoma in. 假設你正在寫一個程序,這個程序可以把用戶的名字從e

4、-mail地址中抽取出來。你會期望用戶的名字就是符號 前面的那部分。但是,如果沒有 這個標志,你的代碼將會怎么 處理呢?代碼還能工作嗎?拋出一個異常嗎?這是否也是一個你需要考慮的邊界條件呢?驗證諸如“e-mail地址、電話號碼、賬號和文件名”等格式化數(shù)據(jù)通常都是簡單明了的。 但是對于結構相對復雜的數(shù)據(jù)又該怎么處理呢?假設你正在閱讀某一類報告數(shù)據(jù),其中包括一個頭部記錄,這個頭部記錄鏈接到了一些數(shù)據(jù)記錄,最后是尾部記錄。 我們需要測試多少種情況呢?如果沒有頭部記錄,只有數(shù)據(jù)記錄和尾部記錄,要怎樣處理?如果沒有數(shù)據(jù)記錄,只有頭部記錄和尾部記錄,要怎樣處理?如果沒有尾部記錄,只有頭部記錄和數(shù)據(jù)記錄,要

5、怎樣處理?如果只有一個尾部記錄,要怎樣處理?如果只有一個頭部記錄,要怎樣處理?如果只有一個數(shù)據(jù)記錄,要怎樣處理?就像那個簡單的e-maid地址的例子一樣,必須考慮到:如果數(shù)據(jù)不能像你期望的那樣與 結構相一致,將會出現(xiàn)什么情況。當然,如果你正在創(chuàng)建一個像 e;mail地址這樣的數(shù)據(jù)(可能根據(jù)不同的信息來源來創(chuàng)建 ) 或者具有如上結構的數(shù)據(jù),你就需要測試你的結果并確保其一致性。5.2有序性另一個需要考慮的方面是數(shù)據(jù)的順序,或者是在一個很大的數(shù)據(jù)集合中某一數(shù)據(jù)的位 置。比如在前一章中所列舉的largest。的例子中,一個bug是否會暴露出來,取決于你所查找的最大值是否是位于 list的最前或者最后。

6、這是有序性的一個方面。任何一種搜索程序都應該針對搜索目標位于最前或者最后的條 件做測試,因為許多常見的bug在這種情況下都能找出來。有序性還包含另一個方面。假設你正在寫一個函數(shù),它接收一個包含餐館菜單的集合。 你期望開胃菜排在菜單的第一位,接著是沙拉(以及所有重要的調味品),然后是主菜,最后是甜點和巧克力。如果最前是甜點,主菜在最后,那你的代碼怎么來處理?如果這種情況可能發(fā)生, 并且在發(fā)生的時候, 你的程序需要處理它, 那么你就需要測試 這種情況,并且把這個問題說清楚。現(xiàn)在,也許你的方法并不需要擔心這種情況。 或許應該 在用戶的輸入層就解決這個問題 (參見后面的“測試無效參數(shù)” )。如果你正在

7、寫一個排序函數(shù),在集合已經有序的情況下,可能會出現(xiàn)什么情況呢?或者更糟糕的,原集合已經反向排序好了,會出現(xiàn)什么情況呢?詢問你自己這是否會導致問題一這些問題是否也值得編寫一個測試。如果你的方法是讓某些元素維持有序,就應該檢查一下它們是否真的有序。假設你有一個方法,它屬于 GUI的一個部分,負責把點餐菜單發(fā)送到廚房,那么你就應該做一個測試 來保證菜單上的菜目順序符合正確的上菜順序:public voidtestKitche nO rder()Order order =new Order();Fooditem desert =Fooditem entree =Fooditem salad =new

8、Desert( Chocolate Decade nee);new Entree( Beef Oscar ););new Salad( Tossed , Parmesa n Peppercor n/ Add out of order order.addFooditem(desert); order.addFooditem(e ntree); order.addFooditem(salad);/ But should come out in serv ing order Iterator itr = order.iterator();assertEquals(itr.next(), salad)

9、;assertEquals(itr.next(), entree);assertEquals(itr.next(), salad);/ No more left assertFalse (itr.hasNext();當然, 從客戶的角度來看, 你需要把代碼修改得足夠靈活, 這樣可以讓他們在別人都吃 沙拉的時候按自己的意愿先吃冰淇淋。 這種情況下, 你需要加一個測試來證實你侄子的冰淇 淋是和其他人的沙拉是一起上的,而祖母的冰淇淋則是和你的咖啡一起上的。5.3 區(qū)間性Range(區(qū)間)是一個針對所有類似下列情景的單詞:對于一個變量,它所屬類型的取值范 圍可能比你需要或想要的更加寬廣。 例如,我們通

10、常使用整型來表示一個人的歲數(shù), 但是顯 然沒有人能夠活到 200 000 歲,盡管 200 000 是一個合法的整型值。類似地,雖然我們是用 整型來存儲角度,但是在一個圓中,角度值不會大于 360 度。在一個好的面向對象設計中,你通常都不會使用一個原生類型(如int, Integer)來存儲一個具有邊界的值,諸如歲數(shù)、羅盤頭指向的角度等 :* Compass bearing */public class Bearing protectedint bearing ; /0.359/* Initialize a bearing to a value from0.359*/public Bearin

11、g(int num_degrees)if (num_degrees359)throw new RuntimeException( Bad bearing ); bearing = num_degrees;/* Return the angle between our bearing and another * May be negative */publicint angleBetween(Bearing anOther)return bearing - anOther. bearing注意,返回的角度值只 .是一個 int 值,因為我們并沒有給返回結果強加任何區(qū)間約束(例 如,它可能會是一個

12、負值)。在上面的代碼中,通過把bearing這個概念封裝到一個類中,你現(xiàn)在就可以在系統(tǒng)中的某處過濾掉那些不合理的值。另外,你也不能創(chuàng)建出一個位于區(qū)間之外的Bearing對象。因此,對于系統(tǒng)中使用Bearing對象的其他部分,現(xiàn)在就可以確認它們包含的肯定是合理的角度值。其他的區(qū)間可能就不是這么顯而易見了。例如,假設你有一個維護了兩對x,y坐標的類。坐標值都屬于整型,并且可以具有任意值;但是,區(qū)間具有如下的約束:這兩個點(兩個坐標代 表的點)必須能夠描述一個所有邊都不大于100個unit的矩形。也就是說,這兩對 x, y值的允許區(qū)間是互相依賴的。因此,對于可能影響其中一個坐標的任何方法,你都需要進

13、行區(qū)間測試,從而確保結果區(qū)間中的兩對x,y值是合法的。既然在多個測試中你都可能需要調用這個區(qū)間驗證,那么我們應該實現(xiàn)一個新的assert方法:publicstatic final int MAX_DIST = 100;publicvoid assertPairRa nge(Stri ng message, Point one, Point two)assertTrue(message, Math.abs(one.x-two.x) =MAX_DIST );assertTrue(message, Math.abs(one.x-two.x) =0 & next_indexstack.length)。

14、因此,我們需要檢查這一點來確保上面這個表達式是正確的?,F(xiàn)在,next_index和stack都是私有變量 你不會希望只是因為測試而將它們都暴露出來 吧。有幾個辦法可以解決這個問題;目前而言,我們只是在stack中寫了一個叫做 check In varia nt()的特殊方法:throwsIn varia ntExcepti onpublic voidcheck In varia nt()/JDK 1.4 can use assert() in stead=0 &next_indexthrow new In varia ntExcepti on(n ext_ in dex+for stack l

15、en gth+stack . length);現(xiàn)在測試程序就可以調用check In varia nt(),從而在不直接訪問這些變量的前提下,確保stack class的內部沒有出現(xiàn)越界行為。public class TestMyStackexte ndsTestCasepublic void testEmpty()throws IMyStack stack =new MyStack();stack.check In varia nt(); stack.push( sample );stack.check In varia nt();/Popp ing last eleme nt okasse

16、rtEquals( sample , stack.pop(); stack.check In varia nt();/Delete from empty stackstack.delete(1);stack.checkInvariant();當你運行這個測試時,你很快就會發(fā)現(xiàn)我們確實需要加入一些區(qū)間檢查。并非完整例子,缺少異常處理,暫不給出測試結果截圖在一個簡單的測試環(huán)境中,發(fā)現(xiàn)并解決這一類錯誤與等到該錯誤都隱藏到應用程序中時才尋找錯誤相比,這種做法要簡單得多。幾乎所有的索引概念(無論是否為整型索引)都應該被大量地測試。這里有一些建議供你 開始測試時參考:開始索引和結束索引有相同的值。第一個索

17、引值大于最后一個索引值。索引值是負的。索引值大于允許值。Count不能匹配確切索引的個數(shù)。5.4引用、耦合性你的程序引用了哪些位于程序之外的事物?或者任何外部依賴?類應該處于什么樣的狀態(tài)?程序運行還需要存在哪些其他的條件?例如,網(wǎng)站上一個用來顯示用戶賬號記錄的方法,可能要求用戶先登錄。棧的PoP ()方法要求一個非空的棧。給汽車換擋,使其從運行擋轉換到停車擋,要求汽車最后是停著的。如果對于類的狀態(tài)、其他對象的狀態(tài),或者全局應用程序的狀態(tài),你需要做一些假設,那么你就需要對代碼進行測試,保證其在假設未滿足的情況下運行良好。例如,汽車微處理控制傳動器的代碼可能有一組用來檢查以下特殊情況的測試:傳動器

18、的狀態(tài)(是否切換到停車擋)取決于汽車的狀態(tài)(處于移動狀態(tài)還是停車狀態(tài) )。public void testJamltl ntoPark()tran smissio n.select(DRIVE);car.accelerateTo(35);assertEquals(DRIVE, tran smissio n.getSelect();/should sile ntly ignoretran smissio n.select(PARK); assertEquals(DRIVE, tran smissio n.getSelect(); car.accelerateTo(O);i.e stopcar.b

19、rakeToStop();/should work nowtran smissio n.select(PARK); assertEquals(PARK, tra nsmissio n.getSelect();一個已知方法的前條件(preconditions)是指:系統(tǒng)必須處于什么狀態(tài)下該方法才能運行。 在上面的例子中,使傳動器停止的前條件就是汽車的發(fā)動機(應用程序系統(tǒng)中的一個分離部件)必須停止。這是該方法必須滿足的文檔化要求,因此我們需要確認:當前條件不能滿足的時候,程序的行為仍然是正確的(在這一特殊情況下,傳動器將忽略其請求)。在方法的最后,后條件(postconditions)是指你的方法

20、將會保證哪些狀態(tài)發(fā)生。程序直接返回的結果顯然是要檢查的,但如果程序具有任何副作用,那你也需要對它們進行檢查。 在上面的例子中,剎車就具有令車停下來的副作用。5.5存在性通過詢問下面的問題,你也許就能夠發(fā)現(xiàn)許多bug: “給定的事物存在嗎?”對于你傳入或者維護的值,先詢問自己如果值不存在如果它為null或者空值,或者等于0,方法的行為將會怎么樣?面對這些不存在的數(shù)據(jù),Java庫的許多方法會拋出某種異常。然而要調試一個隱藏在庫深處的運行期異常通常并不容易,這也正是問題所在。然而,報告諸如“Age isnt set ”的異常通常都能夠讓我們很容易地捕獲到問題所在。在期望值不存在的時候,大多數(shù)方法都會

21、失?。坏@可能并不是你所期望的結果。因此,你可以對這些情況進行測試一一查看當由于某些查詢失敗,你獲得了一個null而不是CustomerRecord的時候,發(fā)生了哪些事情;或者當網(wǎng)絡不通、文件不存在的時候,又會發(fā)生 什么事情。Ah, yes:環(huán)境中的任何事物并不能保證其肯定存在一一網(wǎng)絡、文件的URL、許可碼、用戶、打印機一等等其他你能列舉的事物。當你期望它們存在的時候,它們可能并不存在;因此,你要確認你已經做了足夠的測試:null, 0、空字符串和其他與存在性相關的陷阱。確認你的方法處理了 “不存在”的情況。5.6基數(shù)性這里的基數(shù)指的是計數(shù)(counting )。計算機程序員對于計數(shù)并不擅長,

22、特別是在不能用十個指頭幫著數(shù)的時候。比方說,快速地回答以下的問題,就用你的大腦,別用指頭、白紙、或者UML等來幫忙:假如你有12英尺的院子需要用樁子圍起來,而相鄰樁子的間隔為3英尺,你需要多少個樁子呢?如果你和我們中的大多數(shù)一樣,你可能想都沒想就答 4了。不幸的是,這是錯誤的答案你需要5個籬笆樁,如圖5.1 o這個例子,以及類似的常見錯誤,因為出現(xiàn)得太多了,所 以人們就給它取了一個優(yōu)雅的名字界樁錯誤(fencepost error) ”。3 feet3 feet3 feet3 feet-12 feet圖51 姐篙笆樁事實上,上面只是off by one ”錯誤的一種形式而已,而且這種偶然性的致

23、命錯誤時常會折磨許多程序員。因此,你需要想出辦法來測試你的函數(shù)是否能夠正確計數(shù),并且檢查最后的計數(shù)值。這是一個和存在性相關的問題,但是你現(xiàn)在需要確信:你計算得到的數(shù)目和你所需要的數(shù)目是一致的。在大部分情況,你只須考慮下面3種值:1. 零2. 一3. 多于一這被稱為 O-1-n原則”,這里有個前提是你能處理多于一個的情況。對于你而言,也 許處理10, 20或者1000都是小菜一碟。在大多數(shù)情況下也確實如此 ;因此,我們針對基數(shù)性 的測試主要是考慮:我們是否具有兩個或者多個測試對象。當然,在某些情況下,具體數(shù)目 的不同也可能會引人一些差異一一對你而言,10或者250可能會是一個很重要的數(shù)值。假設你

24、正在維護一個薄烤餅店中被訂購食物的一個前十名列表。每次一個訂單下來,你必須調整前十個條目。同時,你還需要以實時數(shù)據(jù)的形式,把當前的前十個條目發(fā)送到薄餅店老板的PDA上。此時,你需要測試哪些內容呢?當列表條目還不足十個的時候,能出報表嗎?當列表空無一物時,能出報表嗎?當列表只有一個條目時,還能出報表嗎 ?當列表還沒有十個條目時,能添加一個新的條目嗎?當列表什么都沒有時,能添加一個新的條目嗎?當列表條目數(shù)為一時,能添加一個新的條目嗎?要是菜單本身就沒十個條目,怎么辦 ?那要是菜單中沒有任何條目,又怎么辦?看了你給出的列表之后,老板現(xiàn)在改變主意了。他想要一個前二十位的列表。這時你要做哪些修改呢?正確

25、的答案是“一行代碼”,類似下面的代碼:Private final static int NUMBER_TO_RETAIN = 20;現(xiàn)在,老板又不喜歡長長的列表,要你把它改成只列出前五位的列表(畢竟他的PDA是相當小的);你可以回到上面那一行代碼,改變那個數(shù)字。而測試應該能夠自動更正,因為它 使用的是同一個屬性,而不是具體的值。public int getMaxE ntries()return NUMBER_TO_RETAIN;因此,測試最后將專注于0、1和n這樣的邊界條件上,其中n的數(shù)值也很可能會隨著業(yè)務需求而變化。5.7時間性CORRECT縮寫中的最后一個邊界條件是Time。你需要始終記得

26、以下這些與時間相關的方面:相對時間(時間上的順序)。絕對時間(消耗的時間和鐘表上的時間 )。并發(fā)問題。一些接口會擁有自己的狀態(tài) ;因此,為了維持這些內部狀態(tài), 你期望login()會在logout() 之前被調用,prepareStatement()會在 executeStatement()之前被調用,connect()在 read()之前被 調用,而read()又在close()之前被調用,等等:要是這些函數(shù)的被調用順序出錯,會如何?也許你應當嘗試使用非預期的順序來調用這些方法。譬如,試著跳過第一個、 最后一個或者序列中間的某一個過程。就如前面例子中數(shù)據(jù)的順序可能會給你帶來麻煩一樣,現(xiàn)在的順序指的是函數(shù)被調用的順序。相對時間也許還包括代碼中的超時問題:為了獲得一個存活期較短的資源,你的函數(shù)會等待多長時間。 如我們后面簡短討論的, 你需要在你的代碼中驗證可能的出錯條件, 包括超 時出錯等??赡苣阋呀浻龅竭^未受超時保護的情形你能想出代碼由于等待子一些永遠不 能得到的資

溫馨提示

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

評論

0/150

提交評論