原創 lightcity 光城 2019-09-17收錄于話題#C++那些事53個
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 |
---|---|---|
condition ; | | condition is true |
| | condition is false |
數值型資料檢查
expected actual | | expected actual |
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();
傳回失敗:
| |
// 傳回成功與否
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);
// 浮點型
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();
}