在使用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)烈推薦閱讀!