天天看點

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

點選檢視第一章 點選檢視第二章

第3章

決策表

幾十年來,人們一直使用決策表技術表達和分析複雜的邏輯關系。決策表具有嚴格的形式化,善于分析事件的完整性與判斷事件的備援性和一緻性。此外,它還支援特定情況下的編譯[CODASYL 1978]。決策表非常适合分析不同條件集情況下的行為組合。決策表也可以提供一個架構,以指導客戶和開發者清晰地描述需求。表3-1描述了一些基本的決策表術語。

3.1 定義與表示法

決策表分為4個部分:粗豎線的左側是樁,右側是入口,粗橫線的上面是條件,下面是行為。是以,我們可以将其分别稱為條件樁、條件入口、行為樁、行為入口。入口部分的每一列是一條規則。如果某個行為與某個規則相對應,那就是說,在那種情況下應該采取這種行為。在表3-1所示的決策表中,如果條件c1、c2、c3都為真,那麼行為a1、a2就都發生(規則1)。如果c1和c2都為真而c3為假,那麼行為a1和a3發生(規則2)。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

如果使用二進制條件(真/假、是/否、0/1),則決策表的條件部分就是一個旋轉90°的根據命題邏輯得到的真值表。這種結構確定能夠考慮到每個條件值的可能組合。在對軟體的描述過程中,決策表并不是一種必不可少的表達形式,它隻是一種說明性的表達。因為決策表中的條件并沒有指定特殊的順序,是以選中的行為也不會以特定的順序發生,而且規則也可以用任何順序來編寫。

如果使用表3-1所示形式描述軟體行為,我們通常會将正常情況放在前幾條規則中來表示,而将異常情況放在後幾條規則中來表示,這樣會使決策表比較易懂。

定義:如果決策表中所有的條件都是二進制格式的,那麼我們稱之為有限入口決策表,表示為LEDT。

帶有n個條件的有限入口決策表,它帶有2n個不同的規則。

定義:如果某個決策表中所有的條件都具有可選的有限數值(>2),那麼我們稱之為擴充入口決策表,表示為EEDT。

定義:如果決策表中有部分條件帶有可選的有限數值,其他都是嚴格的二進制格式,我們稱之為混合入口決策表,表示為MEDT。

決策表假設所有用于評估條件的數值,對于表格的規則執行都是可用的。決策表中的行為可以改變變量值,這可能使決策表發生“?循環表格?”的行為。這就帶來一個層次調用的問題:決策表中的行為可能會引用其他決策表。

3.2 技術詳解

決策表嚴格的結構能支援某些代數運算。

3.2.1 決策表的精簡

如果兩個或多個規則有相同的行為入口,那麼必有某個條件能在一個規則裡面為真,而在另一個規則中為假。很明顯,該條件在這些行為中沒有起到任何作用,而這個行為會在其他規則中執行。是以表3-2可以将規則3和規則4精簡,同理,也精簡了規則7和規則8。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

定義:如果某個條件對于由兩個規則執行的行為沒有影響,那麼該條件的規則入口就是一個無關入口,通常使用長橫線(—)辨別。

規則3和規則4中,c3的入口就是一個無關入口。無關入口有兩個主要的解釋:該條件是無關的,或者該條件不能實施。有時候人們對後一種情況,使用“?n/a?”符号辨別該條件。由于在表3-1中,同樣的行為發生在規則3和規則4中,條件c3對于行為集就沒有影響,是以其被無關入口的長橫線所取代。同理,請見規則7和規則8。

借助布爾代數的知識可以更加理論化地解釋這個問題,在一個良好形式化的決策表中規則應該是互斥的,是以第一個精簡可以簡單地了解為如下過程。

規則3:(c1 ^ (~c2) ^ c3)→a4

規則4:(c1 ^ (~c2) ^ (~c3))→a4

是以兩條規則的互斥就是:((c1 ^ (~c2) ^ c3)→a4))⊕((c1 ^ (~c2) ^ (~c3))→a4)。

這樣可以得出:

((c1 ^ (~c2)) ^ (c3⊕(~c3))→a4

由于(c3⊕(~c3))永遠為真,是以(c1 ^ (~c2))→a4。

3.2.2 有互斥條件的決策表

如果條件與等價類相對應,那麼決策表就具有了比較明顯的特性。表3-3所示決策表中的條件是部分月曆問題,它們對應的是月份變量的互斥等價類。因為它們是互斥的,是以不可能在某個規則中看到兩個入口都為真。此處仍然使用無關入口長橫線(—)。在這種情況下,它實際的意思是“?一定是錯的?”。有些資深的決策表使用者會使用F!來強調這一點。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

使用無關入口有個小問題,那就是如何确定完整的決策表。對于有限入口決策表來說,如果存在n個條件,就必須存在2n個不同的規則。如果無關入口的确表明某個條件是無關緊要的,那麼我們可以通過如下方法計算規則的數目:不包含無關入口的規則視為一條規則,規則裡面隻要有無關入口,就将無關入口的數目乘以2加入該規則的數目。表3-2中最下面一行就是壓縮規則的數目,規則數目之和為8(23)。表3-3中決策表的規則數目也顯示在表格的最底下一行。注意,其規則數之和是12(理應如此)。

如果我們将這種簡單的算法用在表3-3的決策表中,我們就可以獲得表3-4所示的規則數目。但是,我們應該隻有8(23)條規則,是以肯定什麼地方出了問題。為了找到問題所在,展開這三條規則,将無關入口替換成表3-5所示的T和F。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

注意,在規則1、5、9裡面,所有入口都是T,在規則2、3、6、7、10和11中,其中兩個條件都是真。如果将這些不可能的規則都删除,我們就隻剩下3條規則。這個過程的結果如表3-6所示,其中删除了不可能的規則,使用F?!(必定為假)來強調互斥關系。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.2.3 備援和不一緻的決策表

在識别、設計并開發一個完整的決策表過程中,需要對它的備援和不一緻性進行充分的分析。表3-7所示的決策表就是備援的,即3個條件對應9條規則(規則9與規則4是完全一緻的)。為什麼會這樣呢?這很可能就是由一個能力不足的設計者所實作的決策表。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

注意,規則9的行為入口與規則1~4的是一緻的。隻要備援規則裡面的行為與決策表中對應部分是一緻的,就沒什麼大問題。如果行為入口不同,如表3-8所示,我們就有大問題了。

如果在表3-8所示的決策表中,我們要處理一件事務,其中c1為真、c2和c3都為假,那麼規則4和規則9都适用,我們可以得出以下兩個結論:

1)規則4和規則9是不一緻的。

2)決策表不具有确定性。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

規則4和規則9是不一緻的,因為行為集不同。整個表格是不确定的,因為沒法判斷應該使用規則4還是規則9。

3.2.4 決策表引擎

盡管決策表是一種陳述性的表達方式,但我們還是希望盡量将其結構嚴格化,以支援決策表引擎的執行。決策表執行引擎的輸入應該是一個能夠完成某個規則條件入口的所有資訊,而輸出動作應該是該規則對應的行為。但是這裡有個問題,我們很難找到一個簡單的方法來控制輸出行為的順序。不過可以使用整數入口來表示與某個規則對應的行為(而不是簡單的字母形式Xs,例如a1)來表示輸出動作的執行順序。相應的,決策表引擎也可以是互動式的,使用者可以針對決策表中的每一個規則提供一組數值表示。

3.3 案例分析

3.3.1 日期計算函數

因為NextDate函數的輸入變量之間有很有趣的邏輯關系,是以它在軟體測試領域非常有名。NextDate是一個帶有3個變量的函數:年、月、日。它在執行的時候,以年月日的方式傳回下一天的日期。所有數值都有邊界,是正整數,年的邊界是随機的。

1≤月≤12

1≤日≤31

1801≤年≤2100

将NextDate制作成一個決策表,我們需要使用精心選擇的等價類作為條件,請參考[Jorgensen 2009]來擷取更完整的讨論。

M1 = {月:月有30天}

M2 = {月:月有31天除了十二月}

M3 = {月:月是十二月}

M4 = {月:月是二月}

D1 = {日:1≤日≤27}

D2 = {日:日= 28}

D3 = {日:日= 29}

D4 = {日:日= 30}

D5 = {日:日= 31}

Y1 = {年:年是閏年}

Y2 = {年:年是平年}

由于這些類的笛卡兒乘積包括40個元素,是以,我們需要考慮一個帶有40個規則的決策表,如表3-9和表3-10所示,其中很多規則可以被壓縮。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.3.2 汽車刮水器控制器

刮水器是由一個末端帶有撥盤的控制杆控制的。控制杆有4個位置:關(OFF)、Int(間歇)、低(LOW)和高(HIGH)。撥盤有3個位置,分别為1、2、3。撥盤的位置表明3種速度。隻有當控制杆位于Int的時候,撥盤的位置才起作用。下表所示為相對于控制杆和撥盤位置的刮水器速度(次/min)。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

如上所述,我們幾乎可以将其視為一個擴充入口決策表,隻有一點差別,就是表3-11所示的刮水器速度都是獨立的行為(而不是條件有多個數值的情況)。

條件c1和c2隻能表明撥盤和控制杆的狀态,并不能顯示控制杆和撥盤的動作事件,是以這個決策表不能表示出每個狀态的前置狀态,也就是無法表示某種狀态對前置狀态的敏感情況。一般來說,如果控制杆在Int位置,其對應的規則就可以執行到撥盤位置,至少,撥盤位置此時是有意義的。第10章會更加詳細地分析這個模型。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.3.3 鐵路道口門控制器

在伊利諾伊州北部,有一個鐵路道口,楊樹大道和芝加哥西北鐵路在此交叉。在這個道口有3個不同的岔路,每個岔路都有傳感器以感覺火車接近道口或者離開道口。如果沒有火車在道口或者接近道口,道口的門就是打開的。第一列火車過來的時候,門開始降低,當最後一列火車離開的時候,門開始擡升。如果已經有一列火車在道口内,第二列或者第三列火車已到達,那麼門不執行動作,因為門此時已經是放下的狀态。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

表3-12是關于混合入口決策表(MEDT)極好的例子。條件c1類似記憶體,可以通過行為a4和a5予以更新。“不可能規則”在行為a6的入口處顯示。規則1和規則3都不可能,因為如果道口沒有火車,那麼怎麼可能有一個離開的呢?規則13和規則14也是不可能的,因為3個車道都已經被占用了。如果c2和c3都為真(規則5和規則9),那麼“什麼也不做”行為就可以被遞增和遞減的行為取代。但是“什麼也不做”這個行為顯示了這些輸出如何互相抵消。同樣,決策表不表示時間,是以對于“什麼也不做”入口來說,也可能有其他理由。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.4 基于決策表派生的測試用例

基于決策表派生測試用例是可能的,但是過程會比較麻煩。最大的問題是,決策表是陳述性的,是以不能表示其順序。如果決策表已經被優化過,則情況會更糟糕,因為優化過程可能會改變所有或者部分條件、行為和規則。而我們也是以喪失了測試用例中輸入的順序特性,而且決策表的優化過程也可能會隐藏某些有價值的測試用例。

當然,如果設計和開發決策表的過程足夠謹慎,我們還是可以獲得比較完整的資訊的。同樣,也可以辨識出其備援性和不确定性,相應的測試用例就能避免這些問題。然而,因為我們永遠不能自動檢測出缺失的條件或缺失的行為,是以我們隻能獲得有限的完整性。這時候就需要領域經驗了,這也是基于決策表派生測試用例的過程中最好由手工完成的原因。決策表對于計算型應用來說是非常适合的,但是對于事件型驅動應用就差一點。此外,如果事件和資料的上下文與條件樁能夠仔細地分開,那麼我們就能比較容易地識别出上下文敏感的輸入事件。在計算型和決策敏感型應用中,規則是測試用例很好的來源。在事件驅動型應用中,測試用例可能要對應一系列的規則。

3.4.1 保費計算問題的決策表

第1章中提到的保費計算問題幾乎可以直接開發設計為混合入口決策表(MEDT)。年齡和“出險次數”變量已經定義了範圍,可以直接引出擴充入口的條件c1和c2,如表3-13所示。優先減免是兩個布爾量,是以條件c3和c4是有限入口條件。出于節省空間的考慮,表3-13分成4個部分。此處沒有不可能的規則,也沒有“什麼也不做”的行為。拒保條件在表3-13的第四部分。

對于一個應用來說,開發出一個完整的決策表本身就有極大的好處,因為在整個過程中,我們可以確定沒有任何缺失的條件。當然決策表的描述性特質在這裡是一個隐含的問題。基于年齡的罰款系數應該加在因為有錯被罰款之前,否則罰款金額可能不正确。如果使用決策表的絕對描述性特性來生成測試用例,那麼這種事情就沒法避免,此時就需要領域經驗了。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

在保費計算問題中,MEDT裡面有39個不同的規則。每個規則都定義了一個抽象的測試用例,它們也對應第2章保費計算問題流程圖中的路徑。減少這些邏輯用例,生成具體測試用例,這是不能在決策表中完成的。除了一些複合條件中年齡小于16歲或大于90歲的,這39個用例與第2章流程圖中派生出來的用例緊密相關。表3-14可以從表3-13的第一部分派生出來。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

表3-15不能從表3-13中派生出來,但可以從表3-13中的規則裡面手工開發出來。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.4.2 車庫門控系統的決策表

表3-16是針對車庫門控系統的決策表模型。從表中可以看到,在車庫門某個給定的上下文内應該發生的事件(條件c1的入口)。出于空間的考慮,該決策表分成兩部分,第一個部分對應關車庫門的操作,第二部分對應開車庫門的操作。我們也可以看到上下文相關的輸入事件,例如在規則1中,控制信号的響應是,向下起動驅動電機;而在規則5中,對于同樣的輸入事件,是停止電機。表3-16使用了F!(必定為假)辨別符,顯示在每個上下文(有些由不可能的規則所訓示)中被禁止的事件。這裡面也有個約定俗成的模組化傳統:禁止同時發生的事件。在這個表中,由于允許每個上下文的每個事件發生,是以我們有若幹個不可能的規則。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

一個簡單的派生測試用例的原則是,一個規則應該對應一個測試用例。但問題是規則都很短小,隻涉及一個輸入事件。是以,将其了解為激勵/響應對會更好些。在第4章,我們會看到這些基于激勵/響應對的規則與有限狀态機(針對車庫門控系統)描述的事件可以很好地關聯。利用表3-16派生出全部的測試用例是可能的,但隻能手工完成。此時需要領域知識來減少敏感的規則序列,我們使用行為a7(循環表格)來表述這些規則。決策表的陳述特性是另一個複雜的因素,規則的選擇和執行會有一些“?自然?”順序,但這些都沒有表現出來。還有一點,決策表是一次性描述。除非選擇循環表格動作,否則沒法顯示出關門和重新開門等循環。

3.4.3 車庫門控系統的測試用例

從表面上看,車庫門控制器有24個規則,MEDT可以生成24個測試用例。5個“?什麼也不做?”行為(規則4、12、16、20和24)都很奇怪,你怎麼去測試“?什麼也不做?”這樣的事情呢?這些規則中的每一條都涉及光束被打斷這個事件,但這個事件隻有當門關上的時候(規則8)才會激活。這5個“?什麼也不做?”的規則,就是應該被忽略的實體事件。(在第8章,我們會更進一步讨論如何使能和禁用光束傳感器。)有10個不可能的用例(規則2、3、7、10、11、14、15、18、22和23)都是實體上不可能的。它們指的是到達軌道頂端這個事件,而這是不可能發生的。現在就剩下9個真實的測試用例(規則1、5、6、8、9、13、17、19、21)。這些行為都是合法的端口輸出事件,這9個都是具體測試用例。如前所述,它們都是短小的激勵/響應對。我們可以将這些基于規則的、短小的測試用例與規則序列相關聯,進而使其更符合端對端的測試用例要求。表2-3中的5個測試用例在表3-17中以規則序列的方式呈現。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

3.5 優勢與局限

對于邏輯敏感型應用來說,決策表很明顯是一種模組化選擇。如果能将條件表示為帶有依賴關系的等價類(比如NextDate應用),那麼就更适用了。同樣,利用代數簡化過的決策表可以讓我們用更優雅的方式最小化決策表(精簡決策表)。使用決策表的最大問題就是應用中的計算隻能表示成行為,而且無法對行為的順序關系進行表達。最後,輸入事件必須表示為條件,輸出事件表示為行為。有必要再強調一下,不能表示順序關系這一點使得決策表這種方法對于事件驅動的應用顯得不太夠用。表3-18總結了決策表中行為事件的各種表達方式。

3.6 經驗教訓

在20世紀70年代,我是CODASYL決策表任務小組的成員,我們當時需要建立一個針對決策表的“定義性的”描述,包括推薦最終的最佳方案。最終産品由ACM公司出版,是一個加大的紙質文檔的版本。在這個過程中,我們經曆了幾個很有趣的階段。其中之一是,團隊中有一名成員來自比利時,他提議我們應當針對當時正在實施的租賃控制法案制作一個決策表,因為這個法案非常讓人困惑。在後續的一個季度會議中,我們将各自的工作成果彙聚成一個固定的決策表,搞清了這個法案中的很多事情,甚至包括一組不一緻性。

另一個小組成員Lewis Reinwald有一個基于決策表的程式,它可以清除被過度修改過的Fortran程式。通常來說,這些程式是被一群既不懂原始程式也不懂太多之前修改原因的開發人員開發的。在一個測試用例中,Reinwald先生處理了一個非常龐大且維護過度的(簡直就是噩夢)的Fortran程式,該程式有2000多行源代碼。他從源程式中派生出一個簡化的決策表,并手工“清理”了決策表,然後生成了原始程式的改進版本。改進後的版本隻有800行語句。

從1978~1981年,我為一個意大利公司工作。在需求規範化過程中,我們使用有限狀态機的組合,繼而細化成決策表。我們發現,決策表的結構能夠不斷逼迫我們考慮各種可能的場景,而這些場景如果不是因為決策表的活動,那麼可能一直到開發後期才被察覺。

在大學教授的課程裡,我使用了已經通過州立法的關于教師退休計劃獎勵作為例子。在這個例子中我們發現一對會導緻退休福利計算結果混亂的互相沖突的條件。上述3個例子都說明,決策表對于理清複雜的業務規則是非常有效率的。

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章
帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

參考文獻

帶你讀《基于模型的測試:一個軟體工藝師的方法》之三:決策表第3章

繼續閱讀