測試已經成為軟件開發過程中一個至關重要的部分,但近來有三個因素使之扮演了一個甚至更加重要的角色。第一,Microsoft®.NET 開發環境的 誕生戲劇性地改進了開發人員編寫定制測試自動化的能力。那些在 .NET 框架面世以前需要花費數周時間創建的測試程序現在僅用幾小時就可以寫好。第二,正在建立的日益復雜的系統需要更精益求精的測試。最后,軟件安全在軟件開發過程中已不再是事后才 關注的事情,它已成為一個絕對要素。曾經一度推出可能沒有經過完全測試的產品,但這已不再是一個生存選擇。為了幫助你迎接當今測試的挑戰,本專欄將在隨后幾個月的 內容里討論一些關于軟件測試的原則、技巧和最佳實踐。
本月我將從組合在軟件測試中的作用講起。通過編程產生組合的能力使你能有一種強有力的方法來生成測試用例輸入。為了弄清楚什么是組合,現在假定你正在寫一個撲克 牌游戲程序。用手工生成所有可能的五張套測試輸入將是一件令人很不爽的事情。但是用本文的示例代碼,你便可以在分分鐘內做好它:
注意你必須選擇10個字符,同時每個字符必須來自于20個分類中的一個。因此你要一次從20條中選出10個,或 Choose(20,10)——這個函數我將在本 文稍后討論。注意我已經簡化了這個場景。在實踐中,你可能還需要綜合考慮每一組合的排列以及邊界條件和許多其它測試概念。
在此我將用 C# 建立一個組合類,并示范如何使用組合提高測試效果。我想你會發現理解和應用組合及其相關算法是很有裨益的。
Figure 1 組合演示
屏幕的截屏是最佳示范方式。Figure 1 是一個基于 Windows® 的應用程序屏幕,它演示了組合的使用。正如你所看到的,條目(items)的組合是這些條目的一個子集,它們的順序并不重要。在這個例子中我有5個條目——名字 分別為 Adam、Barb、Carl、Dave 和 Eric,——而我感興趣的是大小為3的組合。這里5選3有10種可能的子集:
注意既然順序并不重要,那么我不考慮 { Carl, Barb, Adam } 這樣的子集,因為我認為它和 { Adam, Barb, Carl } 是相同的。Figure 1中所示的例子除了生成組合外,還舉例說明了,我需要計算一個特定大小的條目集和子集能有多少種組合。
數學上的組合是對這種子集思路的概括。取代了任意條目的子集的情況,序列n的一個數學組合是從0到n-1的整數的一個子集。因此一次從4個條目中取2個的數學組合 結果是6個元素(譯注:element為組合中的一組):
{ 0, 1 }{ 1, 2 }
{ 0, 2 } { 1, 3 }
{ 0, 3 } { 2, 3 }
正如我所說的,組合在軟件測試自動化、開發、管理等的方方面面有著非常重要的作用。雖然組合背后的數學概念是古老而艱深,我最近發現,從一般意義上來說,組合 的概念并沒有被軟件工程師們很好地理解,同時,那些可以在 Internet 上獲得的與組合有關的代碼例子多半都是非常低效的,或者在許多情況下,簡直就是錯誤的。
組合
數學組合的三個基本操作如 Figure 2 所示。輸出告訴你當 n = 4,k = 2 時,有六種組合:
{ 0, 2 } { 1, 3 }
{ 0, 3 } { 2, 3 }
從這個例子你可以看到我需要建立某種組合,給定條目總數和子集大小來計算全部組合元素的總數,并且確定某個特定組合元素的后繼者以便我能列出所有組合元素。
稍微細致地考察這些例子,你可以看到組合有兩個重要的特性:條目的總數(數學上通常用 n 表示)和子集的大。ㄍǔS k 表示)。數學組合可以是 0 基 (0-based)或 1 基(1-based)的。我將在這個專欄中通篇使用 0 基計數制,并且分別使用 n 和 k 表示條目總數和在子集中的 條目數。
在我的例子中迄今我已列出的組合元素用的是詞典順序(有時稱為字典順序)。對于數學組合來說,如果以整數來說明,這意味著元素是用增序列出。舉個例子,如果 n = 5,k = 3,第一個元素是{ 0, 1, 2 },那么緊接著的元素是{ 0, 1, 3 },因為12后面是13。還要注意某一組合元素的原子(單個整數)也呈現增序 形式,所以這里有一種雙重排序狀態。
組合的一個重要的函數是對于特定 n 和 k 值的組合元素總數。這個函數大多被稱為 Choose。因此在第一個例子中有 5 個人名的 情況下,我將其寫成 Choose(5,3) = 10,也就是一次從5個條目中選出3個,那么共有10個組合元素。你可能會碰到另外一些標識和命名 Choose 函數的方法,特別是在數學論文中,但 本文我總是使用 Choose。
組合中的 n 和 k 與 Choose 函數中的 n 和 k 是非常容易混淆的。n = 7,k = 4 的數學組合(在7個條目中一次取4個) ,其中有象 { 0, 3, 4, 6 } 這樣的元素,而 Choose(7,4) 函數則返回 35,這是從7個條目中一次取4個的組合元素總數。
組合經常會和排列搞混淆,排列是一組條目所有的可能排列,這時順序是重要的。如果說你有姓名 Alex、Bill、Cris 和 Doug。用詞典順序排列的 話,前三個排列是:{ Alex, Bill, Cris, Doug },{ Alex, Bill, Doug, Cris } 和 { Alex, Cris, Bill, Doug }。
一個組合類
數學組合非常適宜用一個類來實現。你需要數據成員存儲 n 的值(條目總數),k(每個子集元素的條目個數)的值,以及一個數組來保存每個組合元素的“原子”。Figure 3 是表述某個Combination(組合)對象的基本代碼和創建該組合對象第一個詞典元素的構造函數,以及將它表示為一個字符串的代碼。我決定使用C#,但你可以 輕松地將它改編為你所選的任意一種基于 .NET的編程語言。
我將這個代碼放入類庫(Class Library)編譯后,我可以給它增加一個工程選項參數(Project Reference),并從 .NET 控制臺 程序調用它,就象我在此所做的這樣:
Console.WriteLine("\nCombination c(5,3) is initially " + c.ToString()); 下面的輸出將顯示在屏幕上:Combination c(5,3) is initially { 0 1 2 }
當組合類的構造函數進行如下調用時:Combination c = new Combination(5,3);
我在內存中獲得一個對象,它表示五個條目中一次取三個的最初的詞典排序的數學組合元素。內存中的對象可以被表示為如 Figure 4 所示。
Figure 4 內存中的對象
構造函數代碼創建最初的組合元素時是相當簡單的。兩個代表條目總數和子集大小的參數被分別存儲在數據成員 n 和 k 中。因為我處理的數值可能會很大, 所以我決定使用 C# 的 long 類型代替int 類型。如果我愿意的話,我可以用 ulong 類型(無符號 long)獲得雙倍的數值范圍。我用子集的大小 k 來為一個 long 類型的命名數組分配空間,然后用 0 到 k-1 范圍的整數填充每個數據單元。
計算組合元素的個數
現在我已經確定了如何創建一個組合對象,讓我們看看組合的三個基本操作的第二個——根據某個給定的條目總數 n 及子集大小 k 來計算組合元素的總數。舉個例子,如果你處理一次從 n=5 條目中取 k=3,這里有10種可能的組合元素:
{ 0, 1, 3 } { 1, 2, 3 }
{ 0, 1, 4 } { 1, 2, 4 }
{ 0, 2, 3 } { 1, 3, 4 }
{ 0, 2, 4 } { 2, 3, 4 }
我想實現一個 Choose(n,k) 函數,它返回組合元素的個數;Choose(5,3) 返回10。查找現有的Choose 實現,我驚訝地發現 Internet 上的大多數算法都很不耐用。在我向你展示我的 Choose 實現之前,讓我們簡要地審視一下 Choose 函數的標準實現。
編寫 Choose(n,k) 函數的標準方法是直接使用其定義公式。這是一個明顯的但是拙劣解決方案。這里是一個用 C# 編碼的典型 Choose(n,k) 函數 :
文章來源于領測軟件測試網 http://www.kjueaiud.com/