1. 安裝使用
1.1 安裝
在https://code.google.com/p/googletest/ 下載源碼
進入msvc, 注意編譯方式, 如果是dll, 選擇 gtest-md
編譯生成lib文件, 然后引入.文件即可使用
1.2 使用
#include "gtest/gtest.h"
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
當然我們也可以輸出到xml
int _tmain(int argc, _TCHAR* argv[])
{
testing::GTEST_FLAG(output) = "xml:";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
2. 斷言
斷言的宏可以分為兩類ASSERT系列和EXPECT系列。
TEST(StringCmpTest, Demo)
{
EXPECT_EQ(3, add(1, 2));
ASSERT_EQ(3, add(1, 2));
}
我們再來看下所支持的宏
- ASSERT_EQ
- ASSERT_NE
- ASSERT_LE
- ASSERT_LT
- ASSERT_GE
- ASSERT_GT
- EXPECT_EQ
- EXPECT_NE
- EXPECT_LE
- EXPECT_LT
- EXPECT_GE
- EXPECT_GT
- ASSERT_TRUE
- ASSERT_FALSE
- ASSERT_STREQ
- ASSERT_STRNE
- ASSERT_STRCASEEQ
- ASSERT_STRCASENE
- ASSERT_FLOAT_EQ
- ASSERT_DOUBLE_EQ
直接返回成功還是失敗
- FAIL();
- ADD_FAILURE();
Predicate Assertions
在使用EXPECT_TRUE或ASSERT_TRUE時,有時希望能夠輸出更加詳細的信息,比如檢查一個函數的返回值TRUE還是FALSE時,希望能夠輸出傳入的參數是什么,以便失敗后好跟蹤。因此提供了如下的斷言:
- ASSERT_PRED1(pred1, val1);
- ASSERT_PRED2(pred2, val1, val2);
如果對這樣的輸出不滿意的話,還可以自定義輸出格式化
- ASSERT_PRED_FORMAT1(pred_format1, val1);`
- ASSERT_PRED_FORMAT2(pred_format2, val1, val2);
例子
如果我們有這樣一個類Arithmetic
我們只需要新建一個ArithmeticUnit.cpp文件,然后寫下如下代碼:
#include "stdafx.h"
#include "Arithmetic.h"
#include "gtest/gtest.h"
TEST(Arithmetic, add){
Arithmetic arith;
int a(1), b(2);
EXPECT_EQ(3, arith.add(1, 2));
}
3. 深入解析gTest
首先從TEST宏入手, 我們看下宏的定義
//1
define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
//2
#define GTEST_TEST(test_case_name, test_name)\
GTEST_TEST_(test_case_name, test_name, \
::testing::Test, ::testing::internal::GetTestTypeId())
//3
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
public:\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private:\
virtual void TestBody();\
static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
....
所以
1. 最終展開的宏是繼承自testing::Test類
2. 我們最終寫的代碼是放在TestBody()中的
3. 通過靜態變量test_info_,調用MakeAndRegisterTestInfo對測試案例進行注冊。
看下MakeAndRegisterTestInfo 是如何實現的
TestInfo* MakeAndRegisterTestInfo(
const char* test_case_name,
const char* name,
const char* type_param,
const char* value_param,
TypeId fixture_class_id,
SetUpTestCaseFunc set_up_tc,
TearDownTestCaseFunc tear_down_tc,
TestFactoryBase* factory) {
TestInfo* const test_info =
new TestInfo(test_case_name, name, type_param, value_param,
fixture_class_id, factory);
GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
return test_info;
}
TestInfo對象主要用於包含如下信息:
-
測試案例名稱(testcase name)
-
測試名稱(test name)
-
該案例是否需要執行
-
執行案例時,用於創建Test對象的函數指針
-
測試結果
我們還看到,TestInfo的構造函數中,非常重要的一個參數就是工廠對象
internal::TestFactoryBase* factory
它主要負責在運行測試案例時創建出Test對象
new ::testing::internal::TestFactoryImpl<\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>)
我們再來看下 TestFactoryImpl 是如何實現的
template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
public:
virtual Test* CreateTest() { return new TestClass; }
};
我靠, 這也能算是工廠嗎~
不過總之流程是, 我們要創建一個測試對象的時候,先調用factory的CreateTest()方法 創建TestInfo對象, 再通過 GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);對TestInfo對象進行注冊
UnitTest 是單例
UnitTestImpl 是實現
void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
Test::TearDownTestCaseFunc tear_down_tc,
TestInfo * test_info) {
// 獲取或創建了一個TestCase對象,並將testinfo添加到TestCase對象中。
GetTestCase(test_info->test_case_name(),
test_info->test_case_comment(),
set_up_tc,
tear_down_tc)->AddTestInfo(test_info);
}
這里TestCase對象就出來了
-
TEST宏中的兩個參數,第一個參數testcase_name,就是TestCase對象的名稱,第二個參數test_name就是Test對象的名稱。而TestInfo包含了一個測試案例的一系列信息。
-
一個TestCase對象對應一個或多個TestInfo對象。
總結一下gtest里的幾個關鍵的對象:
- UnitTest 單例,總管整個測試,包括測試環境信息,當前執行狀態等等
- Test 我們自己編寫的,或通過TEST,TEST_F等宏展開后的Test對象,管理着測試案例的前后事件,具體的執行代碼TestBody。
- TestCase 測試案例對象,管理着基於TestCase的前后事件,管理內部多個TestInfo。
- TestInfo 管理着測試案例的基本信息,包括Test對象的創建方法。
一個簡單的UML圖如下