搭建一個(gè)UT測試用例過程中關(guān)聯(lián)和繼承的選擇
首先交代下背景:
在做軟件的UT時(shí)候,框架使用繼承的方式進(jìn)行搭建,如下圖所示:
類CTestCase是一個(gè)父類,包含了所有測試中公用的方法。
其中虛函數(shù)RunTest()作為對外啟動測試的虛接口。
Protect類型的CommonWorks()函數(shù)包含了一些必須的公用操作,包含了不可重入的一些變量和操作,將被具體測試用例調(diào)用。
子類CConcreteTestCaseA是對軟件產(chǎn)品具體某一個(gè)特性的測試:
其中屬性mTestAPara是測試A所獨(dú)有的針對A特性的一些配置參數(shù);
SpecialWorksForCaseA是A特性特殊的一些操作封裝;
繼承的方法RunTest用來實(shí)現(xiàn)具體的對特性A的操作,包括對特殊操作封裝函數(shù)SpecialWorksForCaseA的調(diào)用;
現(xiàn)在的問題是,新出現(xiàn)了一個(gè)特性B,測試它需要調(diào)用CConcreteTestCaseA::SpecialWorksForCaseA,
但是目前已知只有極少部分特性的測試需要調(diào)用這個(gè)操作,其他特性并不需要。
我們可以考慮將B繼承自A,構(gòu)成3層繼承關(guān)系,如下所示:
這樣做的好處在于所有不可重入的變量和方法都會被保護(hù)起來。
但是從邏輯上出現(xiàn)了 “B is a A” 的悖論。
另一種選擇則是使用關(guān)聯(lián)關(guān)系,A與B保持邏輯上的sibling的關(guān)系不變,但是使用關(guān)聯(lián)來實(shí)現(xiàn)一種類似于單一Composite的結(jié)構(gòu),如下所示:
這樣做的好處在于如下幾點(diǎn):
主要的優(yōu)點(diǎn)是保持了A與B邏輯上的關(guān)系正確性,而非“認(rèn)兄為父”;
當(dāng)A已經(jīng)存在的時(shí)候,不需要更多額外的修改就可以完成這種工作;
相比于直接復(fù)制SpecialWorksForCaseA中的操作,當(dāng)A邏輯發(fā)生改變的時(shí)候,更加容易更新;
相比于將SpecialWorksForCaseA提取到父類的CommonWorks的做法,縮減了父類的復(fù)雜性和規(guī)模,邏輯上成立。
缺點(diǎn)在于:
當(dāng)A中的mTestArgs依賴于父類的mTestConfiguration時(shí)候,類CaseA的實(shí)例化需要增加復(fù)雜度。