通過本文可以收穫:google gtest急速入門、google gtest資源網站。 google gtest是什麼 google gtest是谷歌開源的c++單元測試框架,非常的好用。 起碼個人感覺和spring boot自帶的測試框架功能差不太多。 安裝 略過,請參考:GitHub - goo ...
通過本文可以收穫:google gtest
急速入門、google gtest
資源網站。
google gtest是什麼
google gtest是谷歌開源的c++單元測試框架,非常的好用。
起碼個人感覺和spring boot自帶的測試框架功能差不太多。
安裝
略過,請參考:GitHub - google/googletest: GoogleTest - Google Testing and Mocking Framework或網上資料
使用案例分析
本文重點。
目前版本樣例位於:googletest/googletest/samples at main · google/googletest中。
斷言
與spring boot的測試框架類似,gtest判斷樣例是否出錯用的也是斷言。
斷言使用(ASSERT
或EXPECT
)和配合上具體內容,下麵案例應該是一看就懂。
ASSERT
和EXPECT
的區別隻在於一個函數中,如果有多個斷言,ASSERT斷言失敗後當前函數後續部分不會執行了,EXPECT斷言失敗後當前函數的後續部分會繼續執行。
因此兩種具體用哪一個需要看 當前斷言失敗後函數後續還有無意義。
基礎的斷言
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(val1, val2); | EXPECT_EQ(val1, val2); | val1 == val2 |
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 |
字元串比較
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(str1, str2); | EXPECT_STREQ(str1, _str_2); | the two C strings have the same content |
ASSERT_STRNE(str1, str2); | EXPECT_STRNE(str1, str2); | the two C strings have different content |
ASSERT_STRCASEEQ(str1, str2); | EXPECT_STRCASEEQ(str1, str2); | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1, str2); | EXPECT_STRCASENE(str1, str2); | the two C strings have different content, ignoring case |
上面內容並不完整,gtest還有些厲害的功能,比如
ASSERT_NEAR
(ASSERT_NEAR(res, 3.0, 1.0e-11);
)用於斷言數字的接近程度,當然這種功能已經可以由基礎的組合而成了。
個人樣例分析
在配置好環境後來一個最簡單的入門吧。
公司這邊使用的是集成的插件,具體配置vscode + gtest請自行探索。
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*/
#include "gtest/gtest.h"
#include "leetcode24.h" //要測試的函數的頭文件,其中有要測試的函數
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(leetcode24, add1)
{
double res = AddNumbers(1.0, 2.0);
ASSERT_NEAR(res, 3.0, 1.0e-11);
}
編譯後點擊測試即可:
可以觀察到左邊名字和右邊
TEST
巨集中有對應,TEST
的傳入的參數只是名字,沒有其他含義。
這裡是已經測試成功了,除了圖形化也可以在命令行進行測試:
正在執行任務: cd build && cmake --build . --target all && ctest -j14 -C Debug -T test --verbose
[2/2] Linking CXX executable ..\bin\test_leetcode24.exe
UpdateCTestConfiguration from :C:/Users/cWX1274913/Desktop/self/leetcode/leetcode24/build/DartConfiguration.tcl
Parse Config file:C:/Users/cWX1274913/Desktop/self/leetcode/leetcode24/build/DartConfiguration.tcl
Site: P_CDTFC3-N64RRS
Build name: Win32-ninja
UpdateCTestConfiguration from :C:/Users/cWX1274913/Desktop/self/leetcode/leetcode24/build/DartConfiguration.tcl
Parse Config file:C:/Users/cWX1274913/Desktop/self/leetcode/leetcode24/build/DartConfiguration.tcl
Test project C:/Users/cWX1274913/Desktop/self/leetcode/leetcode24/build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 1
Start 1: test
1: Test command: C:\Users\cWX1274913\Desktop\self\leetcode\leetcode24\bin\test_leetcode24.exe
1: Test timeout computed to be: 1500
1: [==========] Running 1 test from 1 test case.
1: [----------] Global test environment set-up.
1: [----------] 1 test from leetcode24
1: [ RUN ] leetcode24.add1
1: [ OK ] leetcode24.add1 (0 ms)
1: [----------] 1 test from leetcode24 (0 ms total)
1:
1: [----------] Global test environment tear-down
1: [==========] 1 test from 1 test case ran. (0 ms total)
1: [ PASSED ] 1 test.
1/1 Test #1: test ............................. Passed 0.10 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.12 sec
* 終端將被任務重用,按任意鍵關閉。
可以看到測試已經成功了,來個失敗的案例吧。
增加兩個test案例,分別是ASSERT
和EXPECT
的失敗案例。
TEST(leetcode24, assertFail)
{
double res = AddNumbers2(1.0, 2.0);
// EXPECT_NEAR(res, 4.0, 1.0e-11);
ASSERT_NEAR(res, 4.0, 1.0e-11);
res = 3;
EXPECT_NEAR(res, 3.0, 1.0e-11);
}
TEST(leetcode24, expextFail)
{
double res = AddNumbers2(1.0, 2.0);
EXPECT_NEAR(res, 4.0, 1.0e-11);
res = 3;
EXPECT_NEAR(res, 3.0, 1.0e-11);
}
運行後的命令行:
test 1
Start 1: test
1: Test command: C:\Users\cWX1274913\Desktop\self\leetcode\leetcode24\bin\test_leetcode24.exe
1: Test timeout computed to be: 1500
1: [==========] Running 3 tests from 1 test case.
1: [----------] Global test environment set-up.
1: [----------] 3 tests from leetcode24
1: [ RUN ] leetcode24.add1
1: [ OK ] leetcode24.add1 (0 ms)
1: [ RUN ] leetcode24.assertFail
1: ../test/test_leetcode24.cpp:23: Failure
1: The difference between res and 4.0 is 1, which exceeds 1.0e-11, where
1: res evaluates to 3,
1: 4.0 evaluates to 4, and
1: 1.0e-11 evaluates to 9.9999999999999994e-12.
1: [ FAILED ] leetcode24.assertFail (0 ms)
1: [ RUN ] leetcode24.expextFail
1: ../test/test_leetcode24.cpp:32: Failure
1: The difference between res and 4.0 is 1, which exceeds 1.0e-11, where
1: res evaluates to 3,
1: 4.0 evaluates to 4, and
1: 1.0e-11 evaluates to 9.9999999999999994e-12.
1: ../test/test_leetcode24.cpp:34: Failure
1: The difference between res and 4.0 is 1, which exceeds 1.0e-11, where
1: res evaluates to 3,
1: 4.0 evaluates to 4, and
1: 1.0e-11 evaluates to 9.9999999999999994e-12.
1: [ FAILED ] leetcode24.expextFail (0 ms)
1: [----------] 3 tests from leetcode24 (0 ms total)
1:
1: [----------] Global test environment tear-down
1: [==========] 3 tests from 1 test case ran. (0 ms total)
1: [ PASSED ] 1 test.
1: [ FAILED ] 2 tests, listed below:
1: [ FAILED ] leetcode24.assertFail
1: [ FAILED ] leetcode24.expextFail
1:
1: 2 FAILED TESTS
1/1 Test #1: test .............................***Failed 0.04 sec
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 0.06 sec
可以看到leetcode24.assertFail
有一處失敗,而leetcode24.expextFail
有兩處失敗。這 驗證 ASSERT斷言失敗後續不會再執行,而EXCEPT斷言失敗後續還會繼續執行。
TEST_F巨集
TEST_F巨集的作用在於幫助很多類似的處理進行批量測試。如果我們使用的測試集需要使用一些相似的數據呢?或者有些相似的檢查方法?這時就需要用到測試夾具和TEST_F巨集配合了。
測試夾具和TEST_F巨集 的最大的作用就在於測試開始之前和測試完成之後可以執行對應的函數,
SetUp
和TearDown
兩個虛函數。
#include "sample3-inl.h"
#include "gtest/gtest.h"
// To use a test fixture, derive a class from testing::Test.
class QueueTest : public testing::Test {
protected: // You should make the members protected s.t. they can be
// accessed from sub-classes.
// virtual void SetUp() will be called before each test is run. You
// should define it if you need to initialize the varaibles.
// Otherwise, this can be skipped.
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() will be called after each test is run.
// You should define it if there is cleanup work to do. Otherwise,
// you don't have to provide it.
//
// virtual void TearDown() {
// }
// A helper function that some test uses.
static int Double(int n) {
return 2*n;
}
// A helper function for testing Queue::Map().
void MapTester(const Queue<int> * q) {
// Creates a new queue, where each element is twice as big as the
// corresponding one in q.
const Queue<int> * const new_q = q->Map(Double);
// Verifies that the new queue has the same size as q.
ASSERT_EQ(q->Size(), new_q->Size());
// Verifies the relationship between the elements of the two queues.
for ( const QueueNode<int> * n1 = q->Head(), * n2 = new_q->Head();
n1 != NULL; n1 = n1->next(), n2 = n2->next() ) {
EXPECT_EQ(2 * n1->element(), n2->element());
}
delete new_q;
}
// Declares the variables your tests want to use.
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
// When you have a test fixture, you define a test using TEST_F
// instead of TEST.
// Tests the default c'tor.
TEST_F(QueueTest, DefaultConstructor) {
// You can access data in the test fixture here.
EXPECT_EQ(0u, q0_.Size());
}
// Tests Dequeue().
TEST_F(QueueTest, Dequeue) {
int * n = q0_.Dequeue();
EXPECT_TRUE(n == NULL);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0u, q1_.Size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1u, q2_.Size());
delete n;
}
// Tests the Queue::Map() function.
TEST_F(QueueTest, Map) {
MapTester(&q0_);
MapTester(&q1_);
MapTester(&q2_);
}
可以看到我們首先需要從 testing::Test 來派生一個自己的測試類QueueTest,在這個類里你可以定義一些必要的成員變數或者輔助函數,還可以定義 SetUp
和 TearDown
兩個虛函數,來指定每個測試集運行前和運行後應該做什麼。後面測試用例的每個測試集應該使用 TEST_F 巨集,第一個參數是我們定義的類名,第二個是測試集的名稱。
這樣就可以避免在很多重覆的測試的時候需要不斷重覆初始化相同的內容了,以及可以利用類的函數來寫一些複雜的運行邏輯。
參考:
https://github.com/google/googletest/blob/main/googletest/samples/sample6_unittest.cc
https://github.com/AngryHacker/articles/blob/master/src/open_source_components/google_gtest.md
我的博客園:https://www.cnblogs.com/swx123
我的github(代碼一般都放在這裡):https://github.com/578223592