如下圖
CMakeLists.txt
googletest:googletest源文件
test_template:模塊的單元測(cè)試文件夾
CMakeLists.txt
main.cpp:運(yùn)行該文件夾中所有.cpp文件的測(cè)試
test_add.cpp:模塊中add功能的測(cè)試文件,其中包括該功能的具體測(cè)試,如下圖
首先當(dāng)然是cmake和make。
make test
,便會(huì)利用ctest運(yùn)行所有模塊的單元測(cè)試注意事項(xiàng):
Googletest主要包括兩方面:gtest和gmock
3.1. gtestgtest主要包括兩種方式:TEST和TEST_F
兩者區(qū)別,TEST宏的作用是創(chuàng)建一個(gè)簡(jiǎn)單測(cè)試,而TEST_F宏用于在多個(gè)測(cè)試中使用同樣的數(shù)據(jù)配置,所以它又叫 測(cè)試夾具(Test Fixtures)每個(gè)測(cè)試都將從測(cè)試類做派生。
由于TEST_F更多是用在C++上,因此本單元測(cè)試主要使用TEST。
TEST(分類名, 測(cè)試名) {測(cè)試代碼
}
通過測(cè)試下面add_int函數(shù),舉例說明
int add_int(int x,int y){return x+y;
}
想要測(cè)試add模塊的add_int功能。如下
//對(duì)于add_int函數(shù)的測(cè)試 分類為TestAddInt,具體創(chuàng)建三個(gè)測(cè)試,分別測(cè)試輸入值的三種情況
//輸入值同為正數(shù)(測(cè)試名為add_int_positive)
TEST(TestAddInt, add_int_positive) {int ret=add_int(10,24);
EXPECT_EQ(ret,34);
}
//輸入值同為負(fù)數(shù)(測(cè)試名為add_int_negative)
TEST(TestAddInt, add_int_negative) {int ret=add_int(-10,-24);
EXPECT_EQ(ret,-34);
}
//輸入值一正一負(fù)(測(cè)試名為add_int_nega_posi)
TEST(TestAddInt, add_int_nega_posi) {int ret=add_int(-10,24);
EXPECT_EQ(ret,14);
}
//通過調(diào)用add_int函數(shù),并利用EXPECT_EQ比較輸出結(jié)果是否符合預(yù)期,從而達(dá)到測(cè)試目的
其中的EXPECT_EQ為斷言的宏,Gtest中,斷言的宏可以理解為分為兩類:
通常情況應(yīng)該選使用EXPECT_,因?yàn)锳SSERT_*在報(bào)告完錯(cuò)誤后不會(huì)進(jìn)行清理工作,有可能導(dǎo)致內(nèi)存泄露問題
常用的斷言宏有以下六類(具體請(qǐng)查看附錄)
mock測(cè)試就是在測(cè)試過程中,對(duì)于某些不容易構(gòu)造或者不容易獲取的對(duì)象,用一個(gè)虛擬的對(duì)象來創(chuàng)建以便測(cè)試的測(cè)試方法。
如:在進(jìn)行單元測(cè)試時(shí),我們想要測(cè)試自己的函數(shù)A
,但是函數(shù)A
卻依賴于函數(shù)B
,當(dāng)函數(shù)B
無法滿足預(yù)期時(shí)就無法對(duì)函數(shù)A
進(jìn)行測(cè)試,主要由于下面幾個(gè)原因:
函數(shù)B
依賴于硬件設(shè)備函數(shù)B
的返回值無法滿足我們的預(yù)期函數(shù)B
尚未實(shí)現(xiàn)這時(shí)就需要對(duì)函數(shù)B
進(jìn)行打樁(仿真mock),使其達(dá)到我們預(yù)期的效果。
而這時(shí)就涉及到了函數(shù)的多態(tài)。C++可以在不修改函數(shù)A
的情況下,通過虛函數(shù)實(shí)現(xiàn)動(dòng)態(tài)多態(tài),將調(diào)用函數(shù)B
修改為調(diào)用仿真mock函數(shù)。而C語言不支持虛函數(shù)。
因此,需要手動(dòng)將函數(shù)A
調(diào)用函數(shù)B
,通過函數(shù)指針,修改為調(diào)用仿真mock函數(shù)。
因?yàn)闀?huì)對(duì)代碼進(jìn)行改動(dòng),所以在利用gmock做單元測(cè)試時(shí),建議能少用就少用,可以自己在測(cè)試函數(shù)中模擬數(shù)據(jù)。
真要用的時(shí)候,記得在測(cè)試完成后,將改動(dòng)的代碼恢復(fù)原樣。
例子如下:
//函數(shù)A,調(diào)用函數(shù)B去處理num
int test_A(int num){if(test_B(num)<=100){return 0;
}
return 1;
}
//函數(shù)B處理num
int test_B(int num){num+=50;
return num;
}
1.先構(gòu)建結(jié)構(gòu)體,包裝輸入函數(shù)B的參數(shù)以及函數(shù)指針
typedef struct ctest{int num;//輸入函數(shù)B的參數(shù)
int (*p_test_B)(struct ctest*);//指針指向 返回值為int型,參數(shù)為ctest類型指針 的函數(shù)
}ctest;
2.修改函數(shù)A中的函數(shù)調(diào)用,將函數(shù)B替換為函數(shù)指針
int test_A(ctest* p_c_struct){//將參數(shù)修改為結(jié)構(gòu)體ctest
if(p_c_struct->p_test_B(p_c_struct->num)<=100){//修改函數(shù)的調(diào)用
return 0;
}
return 1;
}
上述兩個(gè)步驟,需要在源碼中進(jìn)行修改!!!!!!!!
后續(xù)步驟在測(cè)試文件中
3.創(chuàng)建mock類,并定義mock方法
class Mock_FOO{public:
//定義mock方法
MOCK_METHOD1(mock_test_B,int (ctest* p_c_struct));
//其中MOCK_METHOD1最后的數(shù)字1代表參數(shù)有一個(gè),同理若要定義一個(gè)無參數(shù)的mock方法,則MOCK_METHOD0
//mock_test_B為定義的mock函數(shù)名
//int 表示該函數(shù)返回值
//ctest* p_c_struct表示該函數(shù)的參數(shù)
};
4.實(shí)例化mock對(duì)象,并創(chuàng)建mock對(duì)象方法的函數(shù)的C包裝
//實(shí)例化mock對(duì)象
Mock_FOO mocker;
//創(chuàng)建mock對(duì)象方法的函數(shù)的C包裝
int mock_test_B(ctest* p_c_struct){return mocker.mock_test_B(p_c_struct);
}
5.創(chuàng)建測(cè)試?yán)?TEST(TestMock, test_mock) {EXPECT_CALL(mocker, mock_test_B(An())).WillRepeatedly(Return (1000));
//EXPECT_CALL是mock最主要的部分,配合.WillRepeatedly等限制可以實(shí)現(xiàn)在調(diào)用該mock函數(shù)時(shí),自定義模擬各種效果!
//這句的最終效果即為,每當(dāng)test_A調(diào)用mock_test_B時(shí),都會(huì)返回1000
//具體EXPECT_CALL解釋請(qǐng)看附錄!!!
ctest c_struct_foo;
c_struct_foo.p_test_B = mock_test_B;
int ret=test_A(&c_struct_foo);
EXPECT_EQ(ret,1);
}
具體EXPECT_CALL的介紹請(qǐng)看附錄!!!!!!
4. 附錄 4.1. 常用的斷言宏 4.1.1. 布爾型檢查Nonfatal assertion | Verifie |
---|---|
EXPECT_TRUE(condition); | condition is true |
EXPECT_FALSE(condition); | condition is false |
Nonfatal assertion | Verifie |
---|---|
EXPECT_EQ(expected, actual); | expected == actual |
EXPECT_NE(val1, val2); | val1 != val2 |
EXPECT_LT(val1, val2); | val1< val2 |
EXPECT_LE(val1, val2); | val1<= val2 |
EXPECT_GT(val1, val2); | val1 >val2 |
EXPECT_GE(val1, val2); | val1 >= val2 |
Nonfatal assertion | Verifie |
---|---|
EXPECT_FLOAT_EQ(expected, actual); | the two float values are almost equal |
EXPECT_DOUBLE_EQ(expected, actual); | the two double values are almost equal |
在對(duì)比數(shù)據(jù)方面,我們往往會(huì)討論到浮點(diǎn)數(shù)的對(duì)比。因?yàn)樵谝恍┣闆r下,浮點(diǎn)數(shù)的計(jì)算精度將影響對(duì)比結(jié)果。“幾乎相等”是指兩個(gè)值彼此相差 4 個(gè) ULP
4.1.4. 相近值檢查Nonfatal assertion | Verifie |
---|---|
EXPECT_NEAR(val1, val2, abs_error); | the difference between val1 and val2 doesn’t exceed the given absolute error |
例子如下
//測(cè)試10+24=34,而36是否在誤差5的范圍內(nèi)
TEST(TestNEAR, test_NEAR) {int ret=add_int(10,24);
EXPECT_NEAR(ret,36,5);
}
注:整型時(shí)包含邊界,浮點(diǎn)時(shí)因?yàn)榫葐栴},不包含邊界
如EXPECT_NEAR(34,36,2);//測(cè)試成功
如EXPECT_NEAR(34.1 , 34.2 ,0.1);//測(cè)試失敗
Nonfatal assertion | Verifie |
---|---|
EXPECT_STREQ(expected_str,actual_str); | the two C strings have the same content |
EXPECT_STRNE(str1, str2); | the two C strings have different content |
EXPECT_STRCASEEQ(expected_str, actual_str); | the two C strings have the same content, ignoring case (忽略大小寫) |
EXPECT_STRCASENE(str1, str2); | the two C strings have different content, ignoring case (忽略大小寫) |
STREQ和STRNE同時(shí)支持char和wchar_t類型的,STRCASEEQ和STRCASENE卻只接收char*,例子如下
char* test_char( ){char* a="hi";
return a;
}
//測(cè)試test_char返回值是否為"hi"
TEST(TestChar, test_char_EQ) {char* b=test_char();
EXPECT_STREQ(b,"hi");
}
//忽略大小寫
TEST(TestChar, test_char_CASEEQ) {char* b=test_char();
EXPECT_STRCASEEQ(b,"Hi");
}
4.2. EXPECT_CALL的具體介紹EXPECT_CALL(mock_object, method(matcher1, matcher2, ...))
.With(multi_argument_matcher)
.Times(cardinality)
.InSequence(sequences)
.After(expectations)
.WillOnce(action)
.WillRepeatedly(action)
.RetiresOnSaturation();
第1行的mock_object就是Mock類的對(duì)象
第1行的method(matcher1, matcher2, …)中的method就是Mock類中的某個(gè)方法名,比如上述的mock_test_B;而matcher(匹配器)的意思是定義方法參數(shù)的類型,后面詳細(xì)介紹。
第3行的Times(cardinality)的意思是之前定義的method運(yùn)行幾次。至于cardinality的定義,也會(huì)在后面詳細(xì)介紹。
第4行的InSequence(sequences)的意思是定義這個(gè)方法被執(zhí)行順序(優(yōu)先級(jí)),后面舉例說明。
第6行WillOnce(action)是定義一次調(diào)用時(shí)所產(chǎn)生的行為,比如定義該方法返回怎么樣的值等等。
第7行WillRepeatedly(action)的意思是缺省/重復(fù)行為。
結(jié)合該3.2中g(shù)mock的TEST:EXPECT_CALL(mocker, mock_test_B(An())).WillRepeatedly(Return (1000));
//EXPECT_CALL(mocker, mock_test_B(An()))
//mocker即為mock對(duì)象
//mock_test_B即為創(chuàng)建的mock方法。
//An()為匹配器,其中的An表示可以是type類型的任意值,在這里表示ctest *類型的任意值
//.WillRepeatedly(Return (1000))
//表示每次調(diào)用時(shí)都會(huì)返回1000
4.2.1. 匹配器(matcher)用于定義Mock類中的方法的形參的值
包含以下幾種類型
匹配器 | 解釋 |
---|---|
_ | 可以代表任意類型 |
A() or An() | 可以是type類型的任意值 |
匹配器 | 解釋 |
---|---|
Eq(value) 或者 value | argument == value,method中的形參必須是value |
Ge(value) | argument >= value,method中的形參必須大于等于value |
Gt(value) | argument >value |
Le(value) | argument<= value |
Lt(value) | argument< value |
Ne(value) | argument != value |
IsNull() | method的形參必須是NULL指針 |
NotNull() | argument is a non-null pointer |
Ref(variable) | 形參是variable的引用 |
TypedEq(value) | 形參的類型必須是type類型,而且值必須是value |
匹配器 | 解釋 |
---|---|
DoubleEq(a_double) | 形參是一個(gè)double類型,比如值近似于a_double,兩個(gè)NaN是不相等的 |
FloatEq(a_float) | 同上,只不過類型是float |
NanSensitiveDoubleEq(a_double) | 形參是一個(gè)double類型,比如值近似于a_double,兩個(gè)NaN是相等的,這個(gè)是用戶所希望的方式 |
NanSensitiveFloatEq(a_float) | 同上,只不過形參是float |
這里的字符串即可以是C風(fēng)格的字符串,也可以是C++風(fēng)格的。
匹配器 | 解釋 |
---|---|
ContainsRegex(string) | 形參匹配給定的正則表達(dá)式 |
EndsWith(suffix) | 形參以suffix截尾 |
HasSubstr(string) | 形參有string這個(gè)子串 |
MatchesRegex(string) | 從第一個(gè)字符到最后一個(gè)字符都完全匹配給定的正則表達(dá)式. |
StartsWith(prefix) | 形參以prefix開始 |
StrCaseEq(string) | 參數(shù)等于string,并且忽略大小寫 |
StrCaseNe(string) | 參數(shù)不是string,并且忽略大小寫 |
StrEq(string) | 參數(shù)等于string |
StrNe(string) | 參數(shù)不等于string |
基數(shù)用于Times()中來指定模擬函數(shù)將被調(diào)用多少次
基數(shù) | 解釋 |
---|---|
AnyNumber() | 函數(shù)可以被調(diào)用任意次. |
AtLeast(n) | 預(yù)計(jì)至少調(diào)用n次. |
AtMost(n) | 預(yù)計(jì)至多調(diào)用n次. |
Between(m, n) | 預(yù)計(jì)調(diào)用次數(shù)在m和n(包括n)之間. |
Exactly(n) 或 n | 預(yù)計(jì)精確調(diào)用n次. 特別是, 當(dāng)n為0時(shí),函數(shù)應(yīng)該永遠(yuǎn)不被調(diào)用. |
Actions(行為)用于指定Mock類的方法所期望模擬的行為:比如返回什么樣的值、對(duì)引用、指針賦上怎么樣個(gè)值,等等。
行為 | 解釋 |
---|---|
Return() | 讓Mock方法返回一個(gè)void結(jié)果 |
Return(value) | 返回值value |
ReturnNull() | 返回一個(gè)NULL指針 |
ReturnRef(variable) | 返回variable的引用. |
ReturnPointee(ptr) | 返回一個(gè)指向ptr的指針 |
行為 | 解釋 |
---|---|
Assign(&variable, value) | 將value分配給variable |
行為 | 解釋 |
---|---|
Invoke(f) | 使用模擬函數(shù)的參數(shù)調(diào)用f, 這里的f可以是全局/靜態(tài)函數(shù)或函數(shù)對(duì)象. |
Invoke(object_pointer, &class::method) | 使用模擬函數(shù)的參數(shù)調(diào)用object_pointer對(duì)象的mothod方法. |
行為 | 解釋 |
---|---|
DoAll(a1, a2, …, an) | 每次發(fā)動(dòng)時(shí)執(zhí)行a1到an的所有動(dòng)作. |
IgnoreResult(a) | 執(zhí)行動(dòng)作a并忽略它的返回值. a不能返回void. |
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
分享題目:googletest在C語言項(xiàng)目中的使用指南-創(chuàng)新互聯(lián)
地址分享:http://www.chinadenli.net/article22/ihjcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、軟件開發(fā)、網(wǎng)站建設(shè)、ChatGPT
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容