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