C++ 項目之Googletest單元測試
- 2019 年 10 月 6 日
- 筆記
C++ 項目之Googletest單元測試
1.Clion集成Googletest單元測試
Googletest – Google Testing and Mocking Framework
源碼下載地址:
https://github.com/google/googletest/releases
Googletest中包含兩個模組,分別是gtest與gmock,需要分別源碼編譯,編譯完後,到指定目錄去拷貝includes文件夾與.so文件到下面路徑的指定位置.
然後項目中創建ext目錄,裡面分為兩塊
- 第一塊:includes
包含gmock與gtest的include文件,對應於gcc -I參數,頭文件路徑,包含以.h結尾的頭文件
- 第二塊:libs
包含gmock與gtest的libs文件,對應gcc -L參數,庫文件路徑,裡面包含的是一些.so或.dll等動態或靜態鏈接庫
├── ext │ ├── includes │ │ ├── gmock │ │ └── gtest │ └── libs │ ├── gmock │ └── gtest
上述本地項目路徑配置好後,在CmakeLists.txt中進行配置:
# ext set(BASE_INCLUDES ext/includes) set(BASE_LIBS ext/libs) # googletest set(GTEST_INCLUDE_DIR ${BASE_INCLUDES}/gtest/include) set(GMOCK_INCLUDE_DIR ${BASE_INCLUDES}/gmock/include) set(GTEST_LINK_DIR ${BASE_LIBS}/gtest/lib/) set(GMOCK_LINK_DIR ${BASE_LIBS}/gmock/lib/) # 去哪裡找頭文件 相當於gcc/clang 中的-I(i的大寫字母)參數 include_directories(${GTEST_INCLUDE_DIR}) include_directories(${GMOCK_INCLUDE_DIR}) # 去哪裡找庫文件 .so .dll .dylib 相當於gcc 中的-L參數 link_directories(${GTEST_LINK_DIR}) link_directories(${GMOCK_LINK_DIR})
然後為每個test配上鏈接庫即可.
例如,現在有個測試file,文件名為:了l1.cpp
那麼在CmakeLists.txt中配置為:
add_executable(l1 l1.cpp) target_link_libraries(l1 gtest gtest_main)
2.gtest之Helloworld
int main(int argc, char* argv[]) { // 接收命令行參數 testing::InitGoogleTest(&argc, argv); vector<int> x={1,2,3,5}; // EXPECT_EQ使用 for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], 1) << "Vectors x and y differ at index " << i; } RUN_ALL_TESTS(); return 0; }
例如上述就是個完整的例子,每次運行:
testing::InitGoogleTest(&argc, argv);
然後使用:
RUN_ALL_TESTS();
運行所有的Test,每個Test編寫參考後面斷言.
我們看看運行效果:
l1.cpp:113: Failure Expected equality of these values: x[i] Which is: 2 1 Vectors x and y differ at index 1 l1.cpp:113: Failure Expected equality of these values: x[i] Which is: 3 1 Vectors x and y differ at index 2 l1.cpp:113: Failure Expected equality of these values: x[i] Which is: 5 1 Vectors x and y differ at index 3 [==========] Running 0 tests from 0 test cases. [==========] 0 tests from 0 test cases ran. (0 ms total) [ PASSED ] 0 tests. [ FAILED ] 0 tests, listed below: 0 FAILED TESTS
3.gtest初識之斷言
關於斷言Google包裝了一系列EXPECT
和ASSERT
的宏,而EXPECT系列和ASSERT系列的區別是:
EXPECT
失敗時,案例繼續往下執行。-
ASSERT
失敗時,直接在當前函數中返回,當前函數中ASSERT
後面的語句將不會執行。
例如:
TEST(ASSERTTest, ASSERT_VS_EXPECT) { ASSERT_TRUE(10<2); // ASSERT失敗,直接在當前函數中返回,後面語句不執行 ASSERT_FALSE(10<2); EXPECT_EQ(6, Foo(310, 18)); }
每個Test是個宏,Test底層源碼如下:
# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
對應test_case名與test名.
上述程式碼中10<2為False,而使用了ASSERT_TRUE
,該Test後面所有內容就不會執行,如果換成EXPECT_TRUE
則正常運行!
布爾值檢查
Fatal assertion |
Nonfatal assertion |
Verifies |
---|---|---|
ASSERT_TRUE(condition); |
EXPECT_TRUE(condition); |
condition is true |
ASSERT_FALSE(condition); |
EXPECT_FALSE(condition); |
condition is false |
數值型數據檢查
Fatal assertion |
Nonfatal assertion |
Verifies |
---|---|---|
ASSERT_EQ(expected,actual); |
EXPECT_EQ(expected,actual); |
expected == actual |
ASSERT_NE(val1,val2); |
EXPECT_NE(val1,val2); |
val1 != val2 |
ASSERT_LT(val1,val2); |
EXPECT_LT(val1,val2); |
val1 < val2 |
ASSERT_LE(val1,val2); |
EXPECT_LE(val1,val2); |
val1 <= val2 |
ASSERT_GT(val1,val2); |
EXPECT_GT(val1,val2); |
val1 > val2 |
ASSERT_GE(val1,val2); |
EXPECT_GE(val1,val2); |
val1 >= val2 |
字元串檢查
TEST(StringCmpTest, Demo) { char* pszCoderZh = "CoderZh"; wchar_t* wszCoderZh = L"CoderZh"; std::string strCoderZh = "CoderZh"; std::wstring wstrCoderZh = L"CoderZh"; EXPECT_STREQ("CoderZh", pszCoderZh); EXPECT_STREQ(L"CoderZh", wszCoderZh); EXPECT_STRNE("CnBlogs", pszCoderZh); EXPECT_STRNE(L"CnBlogs", wszCoderZh); EXPECT_STRCASEEQ("coderzh", pszCoderZh); //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh); 不支援 EXPECT_STREQ("CoderZh", strCoderZh.c_str()); EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str()); }
其中STREQ和STRNE同時支援char和wchar_t類型的,STRCASEEQ和STRCASENE卻只接收char*
顯示返回成功或失敗
直接返回成功:SUCCEED();
返回失敗:
Fatal assertion |
Nonfatal assertion |
---|---|
FAIL(); |
ADD_FAILURE(); |
// 返回成功與否 TEST(ExplicitTest, Demo) { ADD_FAILURE() << "這行列印失敗 Sorry"; // None Fatal Asserton,繼續往下執行。 //FAIL(); // Fatal Assertion,不往下執行該案例。 EXPECT_TRUE(1==2)<<"1==2 failed!"; // 為了驗證上述失敗後是否執行下面 SUCCEED(); }
異常檢查
分為三個:
EXPECT_NO_THROW(statement);
不拋出異常
EXPECT_ANY_THROW(statement);
拋出任意類型異常
EXPECT_THROW(statement, exception_type);
拋出指定類型異常
TEST(ExceptionTest,et) { // 拋出任意類型異常 EXPECT_ANY_THROW(10/0); //Expected: 10/0 throws an exception. // 拋出指定類型異常 EXPECT_THROW(1/0,int); //Expected: 1/0 throws an exception of type int. }
Predicate Assertions
檢查一個函數的返回值TRUE還是FALSE時,希望能夠輸出傳入的參數是什麼,以便失敗後好跟蹤
例如:
// 預測斷言 bool MN(int m, int n) { return m>n; } //檢查一個函數的返回值TRUE還是FALSE時,希望能夠輸出傳入的參數是什麼,以便失敗後好跟蹤 TEST(PredicateAssertionTest, Demo) { int m = 5, n = 6; EXPECT_PRED2(MN, m, n); //只提供<=5個參數 傳遞參數要與函數MN對應 }
`EXPECT_PRED2(pred2, val1, val2);
ASSERT類似.PRED2可以到PRED5
最多支援5個參數.
浮點型檢查
EXPECT_FLOAT_EQ(expected, actual)
與EXPECT_DOUBLE_EQ(expected, actual)
ASSERT類似.
對相近的兩個數比較:
EXPECT_NEAR(val1, val2, abs_error);
ASSERT類似.
例如:
// 浮點型 TEST(FloatDoubleTest,Demo) { ASSERT_DOUBLE_EQ(1.1,1.1); EXPECT_FLOAT_EQ(1.2,4.0); EXPECT_NEAR(1.234,1.888,0.9); // EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2); // EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2); EXPECT_PRED_FORMAT2(testing::FloatLE,1,0); // LE表示小於等於 也就是value1<=value2 EXPECT_PRED_FORMAT2(testing::DoubleLE,0.1,0.2); }
類型檢查
// 類型檢查 template <typename T> class Tt{ public: void foo() { testing::StaticAssertTypeEq<bool, T>(); // 與下面調用一致就不報錯,否則報錯 } }; TEST(TypeAssertionTest, Demo) { Tt<bool> tt; tt.foo(); }
學習參考自:https://www.cnblogs.com/coderzh/archive/2009/04/06/1430364.html