UT-mocker

摘自----https://blog.csdn.net/xueyong4712816/article/details/34086649

mockcpp使用方法簡明指導(dǎo)

mock工具介紹

mock工具的作用是指定函數(shù)的行為(模擬函數(shù)的行為)柱恤×敲希可以對入?yún)⑦M(jìn)行校驗(yàn),對出參進(jìn)行設(shè)定膛壹,還可以指定函數(shù)的返回值脆炎。

幾個(gè)相關(guān)概念

(1)mock規(guī)范:每個(gè)MOCKER(function)開始慎颗,跟一系列的.stubs待错、.with拗踢、.will等的內(nèi)容的整體岩臣,稱為一個(gè)mock規(guī)范溜嗜。

(2)核心關(guān)鍵字:指stubs/defaults/expects/before/with/after/will/then/id等這些直接跟在點(diǎn)后面的關(guān)鍵字。

(3)擴(kuò)展關(guān)鍵字:指once()/eq()/check()/returnValue()/repeat()等這些作為核心關(guān)鍵字參數(shù)的關(guān)鍵字架谎。 下面炸宵,請看兩段mockcpp的使用規(guī)范示例代碼,其中帶“/”或者“|”的表示在該位置可能有多種選擇谷扣;帶中括號的表示是可選的土全。

mockcpp的特點(diǎn)

(1) 開源捎琐。

(2) mockcpp支持C函數(shù)的mock和虛接口的mock。

(3) VC下裹匙,mockcpp支持cdecl和stdcall調(diào)用約定的函數(shù)瑞凑。(socket/bind/ftp等函數(shù)就是stdcall調(diào)用約定的)

(4) mockcpp的語法清晰、簡單概页,容易理解(參見下面兩個(gè)sample)籽御。

(5) mockcpp的錯(cuò)誤信息提示非常友好,包含完整的mock規(guī)范定義和實(shí)際運(yùn)行情況(參見下面的樣例)惰匙。

Unexpected invocation: the invocation cannot be found in allowed invoking list.

Invoked: add((int)0x1/1, (int)0x2/2)

Allowed:

method(add)

? .stubs()

? .invoked(0)

? .with(eq((int)0xa/10), eq((int)0x14/20))

? .will(returnValue((int)0xc8/200));

(9) mockcpp是強(qiáng)類型檢查的技掏,強(qiáng)類型檢查也是C/C++的一個(gè)優(yōu)勢,比如eq(3)项鬼,如果調(diào)用函數(shù)時(shí)用的參數(shù)是UL哑梳,那么就應(yīng)該用eq((UL)3),對于函數(shù)返回值也是一樣绘盟,聲明的返回值類型應(yīng)該跟mock中定義的一致鸠真。mock中支持類型檢查,可能會發(fā)現(xiàn)更多代碼BUG的龄毡。

C++強(qiáng)類型檢查弧哎,也是為了提高程序安全性,有些問題通過類型檢查在編譯期可以發(fā)現(xiàn)的稚虎,就不需要在運(yùn)行時(shí)再痛苦的定位了。C/C++的強(qiáng)類型檢查是優(yōu)勢偎捎,我們不用把它拋棄了蠢终。

mockcpp的sample代碼

下面,請看兩段mockcpp的使用規(guī)范示例代碼茴她,其中帶“/”或者“|”的表示在該位置可能有多種選擇寻拂;帶中括號的表示是可選的。

一段簡單的mockcpp使用sample代碼:(帶有完整核心關(guān)鍵字)

TEST(mockcpp simple sample)

{

? ? MOCKER(function) / MOCK_METHOD(mocker, method)

? ? ? ? .stubs() / defaults() / expects(once())

? ? ? ? [.before("some-mocker-id")]

? ? ? ? [.with(eq(3))]

? ? ? ? [.after("some-mocker-id")]

? ? ? ? .will(returnValue(1)) / .will(repeat(1, 20))

? ? ? ? [.then(returnValue(2))]

? ? ? ? [.id("some-mocker-id")]

}

下面是一段比較詳細(xì)的mockcpp使用sample代碼:(帶有完整擴(kuò)展關(guān)鍵字)

TEST(mockcpp detail sample)

{

? ? MOCKER(function) / MOCK_METHOD(mocker, method)

? ? ? ? .stubs() / defaults() / expects(never() | once() | exactly(3) | atLeast(3) | atMost(3) )

? ? ? ? [.before("some-mocker-id")]

? ? ? ? [.with( any() | eq(3) | neq(3) | gt(3) | lt(3) | spy(var_out) | check(check_func)

? ? ? ? ? ? ? ? | outBound(var_out) | outBoundP(var_out_addr, var_size) | mirror(var_in_addr, var_size)

? ? ? ? ? ? ? ? | smirror(string) | contains(string) | startWith(string) | endWith(string) )]

? ? ? ? [.after("some-mocker-id")]

? ? ? ? .will( returnValue(1) | repeat(1, 20) | returnObjectList(r1, r2)

? ? ? ? ? ? ? ? | invoke(func_stub) | ignoreReturnValue()

? ? ? ? ? ? ? ? | increase(from, to) | increase(from) | throws(exception) | die(3))

? ? ? ? [.then(returnValue(2))]

? ? ? ? [.id("some-mocker-id")]

}

1丈牢、擴(kuò)展關(guān)鍵字分類: expects里面的叫匹配關(guān)鍵字(Matcher)祭钉; with里面的叫約束關(guān)鍵字(Constraint); will/then里面的叫樁關(guān)鍵字(Stub)己沛。

2慌核、spy的作用是監(jiān)視執(zhí)行該被mock的函數(shù)function被調(diào)用時(shí)傳入的值,會保存在var_out中申尼,供用例中其它地方使用垮卓。

3、outBound的作用是設(shè)置函數(shù)function的出參的值师幕。多半是把該值作為后面部分被測代碼的輸入粟按。(注意與spy區(qū)別)

4、outBoundP,與outBound作用相同灭将,只是用于數(shù)組的情況疼鸟。

5、mirror的作用是對數(shù)組類型的入?yún)⑦M(jìn)行檢查庙曙。(outBoundP是設(shè)置出參的值空镜,兩者是不同的)

6、check的作用是進(jìn)行定制化的入?yún)z查矾利,比如只檢查結(jié)構(gòu)體的部分成員姑裂。可以通過函數(shù)指針或者仿函數(shù)的方式指定男旗,用仿函數(shù)還能預(yù)先保存一些值舶斧,非常方便。(有些mock工具叫它follow)

7察皇、check也能夠用于設(shè)置出參的情況茴厉。

8、die表示程序退出什荣,并且返回指定的值矾缓。它是異常退出,用于模擬一個(gè)函數(shù)調(diào)用崩潰的情況稻爬。

9嗜闻、increase(from, to),表示依次返回from到to的對象桅锄,任何重載了++運(yùn)算符的對象都可以用琉雳。

10、outBound和outBoundP都可以帶一個(gè)約束參數(shù)友瘤,用于對參數(shù)進(jìn)行檢查翠肘,因?yàn)橛型瑫r(shí)作為in和out的參數(shù)。(如:outBound(var_out, eq(3)) )

下面是結(jié)合上面sample的mockcpp使用說明

1辫秧、mock C函數(shù)或者類的靜態(tài)成員方法用MOCKER;

mock 類的非靜態(tài)成員方法需要先用MockObject mocker;聲明一個(gè)mock對象束倍,再用MOCK_METHOD(mocker, method)來mock指定方法。

2盟戏、緊跟著MOCKER/MOCK_METHOD之后的是stubs绪妹、或者defaults、或者expects柿究,三個(gè)必須有一個(gè)喂急。(這是與AMOCK不同的地方,在這個(gè)層次上確定這三個(gè)關(guān)鍵字必須有一個(gè)笛求,可以讓mock語法更清晰)

stubs 表示指定函數(shù)的行為廊移,不校驗(yàn)次數(shù)糕簿。 expects 與stubs的區(qū)別就是校驗(yàn)次數(shù)。(.expects(once()) / .expects(never()) / .expects(exactly(123))) defaults 表示定義一個(gè)默認(rèn)的mock規(guī)范狡孔,但它優(yōu)先級很低懂诗;如果后面有stubs或者expects重新指定函數(shù)行為,就會按照新指定的來運(yùn)行苗膝。(一般用在setup中)

3殃恒、用will指定函數(shù)的返回值;

如果要指定20次調(diào)用都返回1辱揭,則用.will(repeat(1, 20))离唐; 要指定第一次返回1,第二次返回2问窃,第三次返回3亥鬓,就用

? ? ? .will(returnValue(1))

? ? ? .then(returnValue(2))

? ? ? .then(returnValue(3))

如果你指定了前三次的返回值依次為1、2域庇、3嵌戈,那么第四次、第五次調(diào)用听皿,都是返回最后的返回值3熟呛。

4、用id給一個(gè)mock規(guī)范指定一個(gè)名字尉姨,然后可以用after庵朝、before來指定多個(gè)mock應(yīng)該的調(diào)用順序。

注意before在with前又厉,after在with后偿短,id在整個(gè)mock規(guī)范的最后。

5馋没、使用mockcpp時(shí),校驗(yàn)是否按照mock規(guī)范進(jìn)行調(diào)用的降传,應(yīng)該用: GlobalMockObject::verify(); verify之后篷朵,會自動執(zhí)行reset。(如果是對象的mock婆排,應(yīng)該用mocker.verify()声旺,同樣也會自動reset。)

如果單單只想reset段只,也可以:(這很少見腮猖,難道前面你定義的mock規(guī)范都不想要了,也不校驗(yàn)赞枕?那為何要定義呢澈缺?) GlobalMockObject::reset();

一般是在teardown中調(diào)用verify坪创。

6、如果要對某個(gè)函數(shù)(比如add)指定多個(gè)調(diào)用不同的行為(多個(gè)mock規(guī)范)姐赡,比如調(diào)用入?yún)?莱预,2時(shí),返回30项滑;調(diào)用入?yún)?依沮、4時(shí),返回700枪狂。那么可以這樣寫:

MOCKER(add)

? .stubs()

? .with(eq(1), eq(2))

? .will(returnValue(30));

MOCKER(add)

? .stubs()

? .with(eq(3), eq(4))

? .will(returnValue(700));

7危喉、如果對于6的例子,還希望校驗(yàn)次數(shù)州疾,則把stubs改為expects(once())這樣的即可辜限。

8、如果對于6的例子孝治,還希望對調(diào)用順序做嚴(yán)格要求列粪,必須第一次調(diào)用參數(shù)是1、2谈飒,第二次是3岂座、4,那么可以這樣寫:

MOCKER(add)

? .stubs()

? .with(eq(1), eq(2))

? .will(returnValue(30))

? .id("first");

MOCKER(add)

? .stubs()

? .with(eq(3), eq(4))

? .after("first")

? .will(returnValue(700));

9杭措、指定出參的方法(例子中出參為指針類型费什,出參為引用的outBound(var)即可,更加簡單)

void function(int *val)

{

}

應(yīng)該用下面方式來指定出參:

int expect = 10;

MOCKER(function)

? .stubs()

? .with(outBoundP(&expect, sizeof(expect)));

10手素、對同一個(gè)函數(shù)指定多個(gè)mock規(guī)范鸳址,那么這些mock規(guī)范一般是應(yīng)該在輸入方面有差異的,否則沒必要指定多個(gè)泉懦。而且稿黍,在輸入方面無差異的兩個(gè)mock規(guī)范,讓mockcpp內(nèi)部無法判斷是否滿足規(guī)范約束崩哩。 比如巡球,測試函數(shù) void function(int in, int &out),前面一個(gè)是入?yún)⒌肃冢竺嬉粋€(gè)是出參酣栈,希望in為1時(shí),輸出out為100汹押,in為2時(shí)矿筝,輸出out為3,那么應(yīng)該這樣寫:

int out = 100;

MOCKER(function)

? .expects(once())

? .with(eq(1), outBound(out));

out = 3;

MOCKER(function)

? .expects(once())

? .with(eq(2), outBound(out));

假設(shè)你把eq(1)棚贾、eq(2)寫為any()窖维,那么mockcpp會判斷你的兩個(gè)調(diào)用function(1, out)和function(2, out)都符合第一個(gè)mock規(guī)范榆综,從而報(bào)告與你定義的次數(shù)1不匹配。

11陈辱、有時(shí)候需要對同一個(gè)函數(shù)指定多個(gè)mock規(guī)范奖年,并且它們是有規(guī)律的,那么可以借助循環(huán)來簡化代碼沛贪。 假設(shè)要mock的函數(shù)是void function(int in)陋守,希望它依次以0、1利赋、2...10為入?yún)⒈徽{(diào)用水评,每次都調(diào)用一次,那么可以像這樣寫:

MOCKER(function)

? .expects(once())

? .with(eq(0))

? .id("0");

for (int i = 1; i <= 10; i++)

{

? MOCKER(function)

? ? .expects(once())

? ? .with(eq(i))

? ? .after(string(i - 1))

? ? .id(string(i));?

}

12媚送、spy約束關(guān)鍵字應(yīng)用舉例中燥。 spy的作用是監(jiān)視,下面例子塘偎,就是監(jiān)視test在調(diào)用func時(shí)疗涉,傳入的值是多少。有些時(shí)候吟秩,測試用例需要這樣的值咱扣,這種方式是很有效的。

void func(int var)

{

}

void test()

{

? ? int var = 10;

? ? func(var);

}

TEST(sample test)

{

? ? int var;

? ? MOCKER(func)

? ? ? ? .stubs()

? ? ? ? .with(spy(var));

? ? ? ? .with(eq(10));

? ? test();

? ? ASSERT_EQ(var, 10);? ?

}

13涵防、check約束關(guān)鍵字的用法闹伪。 約束關(guān)鍵字中,有很多都是對入?yún)⑦M(jìn)行檢查的壮池,比如eq偏瓤、neq、lt椰憋、gt等等厅克,但它們都只實(shí)現(xiàn)了非常簡單的檢查。 如果用戶想做一個(gè)定制化的檢查橙依,那么就可以用check证舟。 例1:假設(shè)用戶想檢查入?yún)指向的結(jié)構(gòu)的字段b是不是10,那么可以如下這樣寫:

struct AA

{

? ? int a;

? ? int b;

};

void func(int in, AA *p)

{

}

// 實(shí)現(xiàn)一個(gè)檢查函數(shù)票编,入?yún)㈩愋透獧z查的入?yún)⑾嗤祷刂禐閎ool卵渴,返回true表示檢查通過慧域。

bool check_func(AA *p)

{

? ? if ( p->b == 10)

? ? {

? ? ? ? return true;

? ? }

? ? return false;

}

TEST(sample test)

{

? ? MOCKER(func)

? ? ? ? .stubs()

? ? ? ? .with(any(), check(check_func));

? ? func(in, p);

}

例2:如果需要檢查b是否小于某個(gè)給定的數(shù),而且有多個(gè)用例浪读,每個(gè)用例中與b比較的數(shù)不同昔榴,則可以使用仿函數(shù)的方式辛藻。

// 實(shí)現(xiàn)一個(gè)仿函數(shù)類,即重載“()”運(yùn)算符的類互订。

struct CheckFunctor

{

? ? CheckFunctor(int _base) : base(_base){}

? ? bool operator ()(AA *p)

? ? {

? ? ? ? if (p->b < base)

? ? ? ? ? ? ? return true;

? ? ? ? return false;

? ? }

? ? int base;

};

TEST(b should less than 100)

{

? ? MOCKER(func)

? ? ? ? .stubs()

? ? ? ? .with(any(), check(CheckFunctor(100)));

? ? func(in, p);

}

TEST(b should less than 200)

{

? ? MOCKER(func)

? ? ? ? .stubs()

? ? ? ? .with(any(), check(CheckFunctor(200)));

? ? func(in, p);

}

14吱肌、只要打樁了,那么就不會運(yùn)行原函數(shù)仰禽,都是與mock規(guī)范匹配氮墨,運(yùn)行樁。 下面例子中吐葵,對add的入?yún)?规揪、2的情況打樁了,如果調(diào)用了入?yún)?温峭、3的情況猛铅,則會報(bào)告調(diào)用在允許的mock規(guī)范列表中不存在的錯(cuò)誤。

TEST(sample test)

{

? ? MOCKER(add)

? ? ? ? .expects(once())

? ? ? ? .with(eq(1), eq(2))

? ? ? ? .will(returnValue(100));

? ? ASSERT_EQ(100, add(1, 2));

? ? ASSERT_EQ(50, add(2, 3));

}

15凤藏、帶有返回值的函數(shù)奸忽,MOCKER后面必須有will,否則mockcpp認(rèn)為無返回值揖庄,校驗(yàn)時(shí)會發(fā)現(xiàn)返回類型不匹配栗菜。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抠艾,隨后出現(xiàn)的幾起案子苛萎,更是在濱河造成了極大的恐慌,老刑警劉巖检号,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腌歉,死亡現(xiàn)場離奇詭異,居然都是意外死亡齐苛,警方通過查閱死者的電腦和手機(jī)翘盖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凹蜂,“玉大人馍驯,你說我怎么就攤上這事÷耆” “怎么了汰瘫?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長擂煞。 經(jīng)常有香客問我混弥,道長,這世上最難降的妖魔是什么对省? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任蝗拿,我火速辦了婚禮晾捏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哀托。我一直安慰自己惦辛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布仓手。 她就那樣靜靜地躺著胖齐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俗或。 梳的紋絲不亂的頭發(fā)上市怎,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音辛慰,去河邊找鬼区匠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帅腌,可吹牛的內(nèi)容都是我干的驰弄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼速客,長吁一口氣:“原來是場噩夢啊……” “哼戚篙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溺职,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岔擂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后浪耘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乱灵,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年七冲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痛倚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡澜躺,死狀恐怖蝉稳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掘鄙,我是刑警寧澤耘戚,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站操漠,受9級特大地震影響收津,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一朋截、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吧黄,春花似錦部服、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赵抢,卻和暖如春剧蹂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烦却。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工宠叼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人其爵。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓冒冬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親摩渺。 傳聞我的和親對象是個(gè)殘疾皇子简烤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)摇幻,斷路器横侦,智...
    卡卡羅2017閱讀 134,672評論 18 139
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,813評論 0 38
  • 一,apk以進(jìn)程的形式運(yùn)行绰姻,進(jìn)程的創(chuàng)建是由zygote枉侧。 參考文章《深入理解Dalvik虛擬機(jī)- Android應(yīng)...
    Kevin_Junbaozi閱讀 2,846評論 0 12
  • 突然就來了一股冷空氣 毫無防備 我凍的頭疼脖子冷 渾身哆嗦 一路頂著風(fēng)騎行 電動車又慢 冷到透心兒 回到家一碗熱湯...
    唯唯豆奶歡樂開懷閱讀 258評論 0 0
  • 二載春風(fēng)過,物是人已非龙宏。綠意心頭起棵逊,待郵寄一封晴天。
    二月不知素閱讀 158評論 2 1