使用googlemock來模擬全局函數(shù)的實(shí)現(xiàn)

在使用googlemock時(shí),在有些函數(shù)調(diào)用中,可能涉及到未開發(fā)完成的函數(shù)。
這個(gè)時(shí)候就需要對(duì)該未完成的函數(shù)(或者涉及網(wǎng)絡(luò)、數(shù)據(jù)庫的操作函數(shù))進(jìn)行mock。
解決方案出處

下面的代碼中account_update函數(shù)使用了db_update這個(gè)函數(shù),它會(huì)直接調(diào)用數(shù)據(jù)庫,是個(gè)重量級(jí)的依賴。 為了對(duì)這段代碼進(jìn)行測(cè)試, 需要把db_update函數(shù)隔離,怎么處理?

#include <DFHLItem.h>
#include <DHLSRecord.h>
extern int db_update(int, struct DFHLItem *);

void account_update(
    int account_no, struct DHLSRecord *record, int activated)
{
    if (activated) {
        if (record->dateStamped && record->quantity > MAX_ITEMS) {
            db_update(account_no, record->item);
        } else {
            db_update(account_no, record->backup_item);
        }
    }
    db_update(MASTER_ACCOUNT, record->item);
}

方法一:利用C語言的預(yù)處理(在編譯之前進(jìn)行Mock)
先引入一個(gè)頭文件:

#include <DFHLItem.h>
#include <DHLSRecord.h>

extern int db_update(int, struct DFHLItem *);

#include "localdefs.h"

void account_update(
    int account_no, struct DHLSRecord *record, int activated)
{
    if (activated) {
        if (record->dateStamped && record->quantity > MAX_ITEMS) {
            db_update(account_no, record->item);
        } else {
            db_update(account_no, record->backup_item);
        }
    }
    db_update(MASTER_ACCOUNT, record->item);
}

在該頭文件中提供一個(gè)db_update的定義,注意,使用了#define把db_update展開為一段代碼

#ifdef TESTING
...
struct DFHLItem *last_item = NULL;
int last_account_no = -1;
#define db_update(account_no,item)\
    {last_item = (item); last_account_no = (account_no);}
...
#endif

這樣C語言編譯器可以把所有的db_update都替換成{last_item = (item); last_account_no = (account_no);}, 這段代碼會(huì)記錄下最后的item和account_no,可以供測(cè)試中的驗(yàn)證使用
使用宏就會(huì)丟失類型安全,如果邏輯復(fù)雜的話,很容易出錯(cuò)謹(jǐn)慎使用該方法。

方法二: 使用函數(shù)指針(編譯期進(jìn)行mock)
(1)首先寫一個(gè)函數(shù)指針: int (*db_update)(int, struct DFHLItem *)
(2)把原來的db_update 改名為 int db_update_production(int, struct DFHLITem *)
(3) 編寫一個(gè)mock實(shí)現(xiàn) int db_update_mock(int, struct DFHLITem *)
(4) 最后使用條件編譯來制定到底用哪個(gè)函數(shù)

#ifdef TESTING
   db_update = db_update_mock
#else
   db_update = db_update_production
#endif

該方法很靈活, 可以隨意通過函數(shù)指針進(jìn)行替換,還能兼顧類型安全 ,推薦使用。

方法三: 在編譯之后 Link時(shí)候進(jìn)行替換
這就需要編寫包括db_update的庫函數(shù),在link的時(shí)候使用這個(gè)假的庫函數(shù)。 當(dāng)然Link出來的exe文件指示一個(gè)測(cè)試版本。
如果需要函數(shù)很多, 還有db_insert, db_delete等等, 這些函數(shù)都需要在假的庫函數(shù)中進(jìn)行實(shí)現(xiàn), 開銷不小。

看過《修改代碼的藝術(shù)》這本書的人可能對(duì)上面的例子有些眼熟,不錯(cuò),上面的方法和例子就是從這本書中來的。這本書對(duì)于處理遺留代碼提供了大量的方法,強(qiáng)烈推薦閱讀!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容