一、簡介
Google Test也叫gtest,是一個面向C++的單元測試框架。它在Google公司內部使用了多年,並且每天都在上千個項目中進行著單元測試。現在已經成為了C++單元測試的事實標準之一。gtest以其高效、靈活、可移植和可擴展等優點獲得廣泛好評。
二、gtest的基本結構
gtest最基本的結構可以分成兩部分:測試用例和測試夾具。測試用例是指對某一個功能的測試,通常會包含多個測試點。每個測試點對應一個gtest宏:TEST,通過TEST來定義測試用例並添加測試點。測試夾具是在每次測試運行之前和之後執行的代碼,用以準備測試環境和清理測試環境。
下面是一個示例代碼:
#include "gtest/gtest.h" TEST(TestCaseName, TestName) { ...屬於這個測試用例的測試點1... ...屬於這個測試用例的測試點2... ...屬於這個測試用例的測試點3... }
在這個例子中,”TestCaseName”和”TestName”分別是測試用例的名稱和測試點的名稱。在一個測試用例中可以定義多個測試點,但是測試用例名稱必須保持唯一。
三、gtest調試相關
1、gtest調試信息輸出
gtest在測試運行過程中,可以輸出調試信息,從而幫助我們定位問題。在gtest中,使用GTEST_COUT可以方便地輸出調試信息。
下面是一個示例代碼:
#include "gtest/gtest.h" TEST(TestCaseName, TestName) { GTEST_COUT << "This is debug info!" << std::endl; }
在這個例子中,代碼輸出了一條調試信息:”This is debug info!”。輸出的位置將在測試運行結果中顯示。
2、gtest運行調試器
如果我們需要在某個測試點處運行調試器,可以使用gtest的”–gtest_filter”參數來實現。
下面是一個示例代碼:
#include "gtest/gtest.h" TEST(TestCaseName, TestName) { GTEST_COUT << "I am going to break point!" << std::endl; int a = 1; int b = 2; EXPECT_EQ(a + b, 3); }
如果我們想在”EXPECT_EQ(a + b, 3)”處打一個斷點來進行調試,可以按下面的命令來執行:
./test --gtest_filter=TestCaseName.TestName:Test.DoDebugBreakHere
在這個例子中,我們通過在測試點後面加上”:Test.DoDebugBreakHere”的方式,在指定的測試點處讓程序停止。
3、gtest調式內存泄漏檢測
gtest提供了內存泄漏檢測,可以幫助我們檢測程序運行過程中是否有堆內存泄漏。
下面是一個示例代碼:
#include "gtest/gtest.h" class Foo { public: int* data; Foo() { data = new int[100]; } virtual ~Foo() { delete[] data; } }; TEST(TestCaseName, TestName) { GTEST_COUT << "This is to test memory leak!" <data[99] == 0); }
在這個例子中,我們故意將Foo的data成員分配了100個整形內存,但是在Foo的析構函數中只釋放了1個整形內存。這樣就會造成堆內存泄漏。我們可以使用gtest的”–gtest_filter”參數,加上”–gtest_enable_death_test”選項來運行這個測試用例。
./test --gtest_filter=TestCaseName.TestName --gtest_enable_death_test
這樣運行測試用例後,gtest會檢測到內存泄漏,並在屏幕上輸出相關信息。
四、gtest運行方式
gtest有三種運行方式:在命令行運行、在IDE中運行、在自動化構建工具中運行。
1、在命令行運行
在命令行下運行gtest非常簡單,只需要將gtest庫鏈接到測試程序中,然後用”./test”來運行測試程序即可。gtest提供了豐富的啟動選項,如”–gtest_list_tests”,”–gtest_filter”等。
下面是一個運行gtest的例子:
gtest_main.cc:
#include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
下面是編譯gtest庫的默認Makefile:
GTEST_DIR = ../googletest CXXFLAGS += -isystem $(GTEST_DIR)/include CXXFLAGS += -std=c++11 -g -Wall -Wextra -pthread TESTS = first_test.cpp second_test.cpp all : test test : $(TESTS) gtest_main.a $(CXX) $(CXXFLAGS) -o $@ $^ gtest-all.o : $(GTEST_DIR)/src/gtest-all.cc $(GTEST_DIR)/include/gtest/gtest.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc gtest_main.o : $(GTEST_DIR)/src/gtest_main.cc $(GTEST_DIR)/include/gtest/gtest.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest_main.cc gtest_main.a : gtest-all.o gtest_main.o $(AR) $(ARFLAGS) $@ $^
2、在IDE中運行
大多數現代IDE都已經支持gtest的執行,運行gtest的過程就像運行其他可執行程序一樣。以Visual Studio為例,可以使用選項”/MDd”將gtest和測試程序鏈接在一起,然後可以用F5來啟動調試會話。
3、在自動化構建工具中運行
gtest可以與許多常見自動化構建工具一起使用,如Make、Ant、CMake、MSBuild等。下面是使用CMake來運行gtest的一個示例代碼:
cmake_minimum_required(VERSION 3.10.2)
project(MyTest)
enable_testing()
add_executable(MyTest test.cc)
target_link_libraries(MyTest gtest_main gtest)
add_test(MyTest MyTest)
在這個例子中,我們先使用add_executable來定義要測試的程序,然後再使用target_link_libraries將gtest庫鏈接到程序中。最後,我們使用add_test將MyTest這個測試添加到測試套件中。
五、gtest的擴展功能
gtest提供了許多非常有用的擴展功能,讓我們能更好地管理測試用例和測試點,以及對程序進行更細緻的驗證。
1、在gtest中組織測試用例
如果我們需要對一組相關的測試用例進行分類,可以使用gtest的TEST_F宏定義來組織測試用例。在TEST_F中定義fixture類來提供測試夾具。
下面是一個示例代碼:
#include "gtest/gtest.h" class TestFixture: public testing::Test { public: static void SetUpTestCase() {} static void TearDownTestCase() {} virtual void SetUp() {} virtual void TearDown() {} }; TEST_F(TestFixture, TestName) { GTEST_COUT << "This is a test!" << std::endl; }
在這個例子中,TestFixture定義了SetUpTestCase和TearDownTestCase來執行測試夾具的初始化和清理任務,SetUp和TearDown來執行每個測試點的初始化和清理任務。使用TEST_F來定義測試用例和測試點。
2、EXPECT系列驗證宏
gtest提供了一系列EXPECT_*和ASSERT_*宏來對程序進行驗證。EXPECT_*和ASSERT_*宏有一點區別,雖然它們都會做出判斷,但EXPECT_*將驗證結果記錄下來,不管是否驗證成功都繼續執行;而ASSERT_*則在驗證失敗的時候立即停止程序。以下是常用的EXPECT系列驗證宏:
- EXPECT_EQ(val1, val2) – val1 == val2
- 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
- EXPECT_TRUE(condition) – condition is true.
- EXPECT_FALSE(condition) – condition is false.
下面是一個示例代碼:
#include "gtest/gtest.h" TEST(TestCaseName, TestName) { EXPECT_EQ(1, 1) << "1 equals 1"; EXPECT_NE(1, 2) << "1 not equals 2"; EXPECT_TRUE(0 == 0) << "0 == 0"; EXPECT_FALSE(1 == 2) << "1 not equals 2"; }
3、自己編寫gtest擴展功能
我們可以通過編寫gtest插件的方式來擴展gtest的功能。gtest插件可以實現事件響應、輸出擴展、斷言擴展和異常捕獲等功能。
以下是一個gtest插件的實現示例:
#include "gtest/gtest.h" void MyTestEventListener::OnTestStart(const testing::TestInfo& test_info) { std::cout << "Test start: " << test_info.name() << std::endl; fflush(stdout); //刷新輸出緩衝區,即將緩衝區的內容立即輸出 } void MyTestEventListener::OnTestEnd(const testing::TestInfo& test_info) { std::cout << "Test end: " << test_info.name() <listeners(); listeners.Append(new MyTestEventListenerFactory); EXPECT_TRUE(1 == 1); }
在這個示例中,我們編寫了一個gtest插件,用來在測試開始和測試結束時列印一條信息。我們使用listeners.Append將這個插件添加到事件監聽器列表中。在TestName測試點中,我們使用了EXPECT_TRUE宏來對程序進行驗證。
六、結論
Google Test是一個非常好用的C++單元測試框架,具有高效、靈活、可移植和可擴展等優點。通過增強gtest的認識和學習如何使用gtest將有助於我們編寫更高效、更健壯的C++程序。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/293572.html