預(yù)處理的接入點(diǎn)
-
構(gòu)建腳本中的宏定義可以控制將文本解釋為真正的實(shí)現(xiàn)還是假的實(shí)現(xiàn)
-
構(gòu)建腳本中的頭文件搜索路徑可被用來控制接入真正的聲明還是假的聲明
-
頭文件中的防衛(wèi)宏可被用來接入假的聲明以遮擋真正的聲明被包含進(jìn)來
上面第二點(diǎn)通常要求提供同名的頭文件, 而使用不同的構(gòu)建設(shè)置
而第三點(diǎn)不要求同名, 只要使用相同的防衛(wèi)宏,
并保證把包含替代聲明的頭文件放在真正的頭文件前面包含進(jìn)來就可以, 使用同一構(gòu)建設(shè)置即可
編譯鏈接的接入點(diǎn)
-
構(gòu)建腳本中的庫搜索路徑可被用來控制接入真正的實(shí)現(xiàn)還是假的實(shí)現(xiàn)
-
針對(duì)接口編程, 可以控制接入真正的實(shí)現(xiàn)還是假的實(shí)現(xiàn)
-
與針對(duì)接口編程類似, 使用函數(shù)指針/函數(shù)對(duì)象等封裝函數(shù), 可以接入假的實(shí)現(xiàn)
-
使用函數(shù)封裝數(shù)據(jù)訪問, static訪問, new 操作符, 可以子類化以接入假的實(shí)現(xiàn)
-
改造為模板, 可以傳入不同的模板實(shí)參來控制接入真正的實(shí)現(xiàn)還是假的實(shí)現(xiàn)
-
利用名稱作用范圍, 同名局部變量可遮擋其它名字等, 來控制接入真正的實(shí)現(xiàn)還是假的實(shí)現(xiàn)
-
利用對(duì)象的內(nèi)存布局, 直接將某幾個(gè)假的函數(shù)地址組成的 vtable, 強(qiáng)轉(zhuǎn)為被測(cè)類型
運(yùn)行時(shí)的接入點(diǎn)
-
解釋型動(dòng)態(tài)語言, 直接在測(cè)試前重定義
-
編譯型靜態(tài)語言, 運(yùn)行時(shí)修改函數(shù)地址
基本上兩個(gè)原則
例子: 測(cè)試使用了 static 函數(shù), new 操作符的客戶代碼
在 TDD 流行之后, 關(guān)于 Singleton, static 函數(shù), new
操作符等依賴具體實(shí)現(xiàn)的代碼被推薦避免使用. 遺留系統(tǒng)中則不可避免的保留著. 它們被批評(píng)的原因是使它們的客戶代碼難以測(cè)試. 我們可以利用
"使用函數(shù)封裝數(shù)據(jù)訪問, static訪問, new 操作符, 可以子類化以接入假的實(shí)現(xiàn)" 來進(jìn)行測(cè)試.
public
class
SingletonClient {
publicvoid
doSomething(){
SingletonObject service = SingletonObject.instance();
service.execute();
}
}
上面的這個(gè)SingletonClient的doSomething是無法測(cè)試的, 因?yàn)橐昧艘粋€(gè)靜態(tài)函數(shù).
可以把對(duì)靜態(tài)函數(shù)的引用抽取到一個(gè)可覆寫的函數(shù)中來引入接入點(diǎn):
class SingletonClient {
publicvoid
doSomething(){
SingletonObject service = getServiceObject();
service.execute();
}
protected
SingletonObject getServiceObject() {
return SingletonObject.instance();
}
}
這樣測(cè)試時(shí)我們便可以子類化SingletonClient, 只重寫getServiceObject,
便可以針對(duì)這個(gè)子類進(jìn)行測(cè)試, 效果與針對(duì)基類測(cè)試是一樣的(因?yàn)槠渌暮瘮?shù)實(shí)現(xiàn)都相同, 只是依賴的第三方對(duì)象被替換為了假的實(shí)現(xiàn)):
class SingletonClientInTestEnvironment
extends
SingletonClient {
protected
SingletonObject getServiceObject() {
returnnew
SingletonObjectStub();
}
}
例子: C++ 測(cè)試, 用遮蓋技術(shù)(定義同名服務(wù)類), 當(dāng)同時(shí)需要測(cè)真正的服務(wù)類本身時(shí)如何解決鏈接問題? (重定義)
那就不要定義同名的類, #define 一個(gè)宏加一層間接, 恰當(dāng)?shù)臅r(shí)候 #undef. 如果是函數(shù), 可以定義一個(gè)函數(shù)對(duì)象來封裝想假冒的函數(shù),
生成該函數(shù)對(duì)象類型的一個(gè)變量時(shí), 使用與函數(shù)相同的名字, 利用名字的作用域規(guī)則來遮蓋原來的函數(shù).