日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest

發(fā)布時(shí)間:2024/4/11 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、前言

“深入解析”對(duì)我來(lái)說(shuō)的確有些難度,所以我盡量將我學(xué)習(xí)到和觀察到的gtest內(nèi)部實(shí)現(xiàn)介紹給大家。本文算是拋磚引玉吧,只能是對(duì)gtest的整體結(jié)構(gòu)的一些介紹,想要了解更多細(xì)節(jié)最好的辦法還是看gtest源碼,如果你看過(guò)gtest源碼,你會(huì)發(fā)現(xiàn)里面的注釋非常的詳細(xì)!好了,下面就開始了解gtest吧。

二、從TEST宏開始

前面的文章已經(jīng)介紹過(guò)TEST宏的用法了,通過(guò)TEST宏,我們可以非法簡(jiǎn)單、方便的編寫測(cè)試案例,比如:

TEST(FooTest,?Demo)
{
????EXPECT_EQ(
1,?1);
}

?

我們先不去看TEST宏的定義,而是先使用/P參數(shù)將TEST展開。如果使用的是Vistual Studio的話:

1. 選中需要展開的代碼文件,右鍵 - 屬性 - C/C++ - Preprocessor

2. Generate Preprocessed File 設(shè)置 Without Line Numbers (/EP /P) 或 With Line Numbers (/P)

3. 關(guān)閉屬性對(duì)話框,右鍵選中需要展開的文件,右鍵菜單中點(diǎn)擊:Compile

編譯過(guò)后,會(huì)在源代碼目錄生成一個(gè)后綴為.i的文件,比如我對(duì)上面的代碼進(jìn)行展開,展開后的內(nèi)容為:

class?FooTest_Demo_Test?:?public?::testing::Test?
{
public:?
????FooTest_Demo_Test()?{}
private:?
????
virtual?void?TestBody();
????
static?::testing::TestInfo*?const?test_info_;
????FooTest_Demo_Test(
const?FooTest_Demo_Test?&);
????
void?operator=(const?FooTest_Demo_Test?&);
};

::testing::TestInfo
*?const?FooTest_Demo_Test?
????::test_info_?
=?
????????::testing::
internal::MakeAndRegisterTestInfo(?
????????????
"FooTest",?"Demo",?"",?"",
????????????(::testing::
internal::GetTestTypeId()),
????????????::testing::Test::SetUpTestCase,
????????????::testing::Test::TearDownTestCase,
????????????
new?::testing::internal::TestFactoryImpl<?FooTest_Demo_Test>);

void?FooTest_Demo_Test::TestBody()
{
????
switch?(0)
????
case?0:
????????
if?(const?::testing::AssertionResult?
????????????????gtest_ar?
=?
????????????????????(::testing::
internal::?EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(1))?==?1)>::Compare("1",?"1",?1,?1)))
????????????;
????????
else?
????????????::testing::
internal::AssertHelper(
????????????????::testing::TPRT_NONFATAL_FAILURE,
????????????????
".\\gtest_demo.cpp",
????????????????
9,
????????????????gtest_ar.failure_message()
????????????????)?
=?::testing::Message();
}

?

展開后,我們觀察到:

1. TEST宏展開后,是一個(gè)繼承自testing::Test的類。

2. 我們?cè)赥EST宏里面寫的測(cè)試代碼,其實(shí)是被放到了類的TestBody方法中。

3. 通過(guò)靜態(tài)變量test_info_,調(diào)用MakeAndRegisterTestInfo對(duì)測(cè)試案例進(jìn)行注冊(cè)。

如下圖:



上面關(guān)鍵的方法就是MakeAndRegisterTestInfo了,我們跳到MakeAndRegisterTestInfo函數(shù)中:

//?創(chuàng)建一個(gè)?TestInfo?對(duì)象并注冊(cè)到?Google?Test;
//?返回創(chuàng)建的TestInfo對(duì)象
//
//?參數(shù):
//
//???test_case_name:? ? ? ? ? ? 測(cè)試案例的名稱
//???name:??????????? ? ? ? ? ? ? ?? 測(cè)試的名稱
//???test_case_comment: ? ? ? 測(cè)試案例的注釋信息
//???comment:????????????????????? 測(cè)試的注釋信息
//???fixture_class_id:???????????? test fixture類的ID
//???set_up_tc:??????????????????? 事件函數(shù)SetUpTestCases的函數(shù)地址
//???tear_down_tc:?????????????? 事件函數(shù)TearDownTestCases的函數(shù)地址
//???factory:??????????????????????? 工廠對(duì)象,用于創(chuàng)建測(cè)試對(duì)象(Test)
TestInfo*?MakeAndRegisterTestInfo(
????
const?char*?test_case_name,?const?char*?name,
????
const?char*?test_case_comment,?const?char*?comment,
????TypeId?fixture_class_id,
????SetUpTestCaseFunc?set_up_tc,
????TearDownTestCaseFunc?tear_down_tc,
????TestFactoryBase
*?factory)?{
??TestInfo
*?const?test_info?=
??????
new?TestInfo(test_case_name,?name,?test_case_comment,?comment,
???????????????????fixture_class_id,?factory);
??GetUnitTestImpl()
->AddTestInfo(set_up_tc,?tear_down_tc,?test_info);
??
return?test_info;
}

?

我們看到,上面創(chuàng)建了一個(gè)TestInfo對(duì)象,然后通過(guò)AddTestInfo注冊(cè)了這個(gè)對(duì)象。TestInfo對(duì)象到底是一個(gè)什么樣的東西呢?

TestInfo對(duì)象主要用于包含如下信息:

1. 測(cè)試案例名稱(testcase name)

2. 測(cè)試名稱(test name)

3. 該案例是否需要執(zhí)行

4. 執(zhí)行案例時(shí),用于創(chuàng)建Test對(duì)象的函數(shù)指針

5. 測(cè)試結(jié)果?

我們還看到,TestInfo的構(gòu)造函數(shù)中,非常重要的一個(gè)參數(shù)就是工廠對(duì)象,它主要負(fù)責(zé)在運(yùn)行測(cè)試案例時(shí)創(chuàng)建出Test對(duì)象。我們看到我們上面的例子的factory為:

new?::testing::internal::TestFactoryImpl<?FooTest_Demo_Test>

?

我們明白了,Test對(duì)象原來(lái)就是TEST宏展開后的那個(gè)類的對(duì)象(FooTest_Demo_Test),再看看TestFactoryImpl的實(shí)現(xiàn):

template?<class?TestClass>
class?TestFactoryImpl?:?public?TestFactoryBase?{
public:
????
virtual?Test*?CreateTest()?{?return?new?TestClass;?}
};

?

這個(gè)對(duì)象工廠夠簡(jiǎn)單吧,嗯,Simple is better。當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)測(cè)試對(duì)象(Test)時(shí),調(diào)用factory的CreateTest()方法就可以了。?

創(chuàng)建了TestInfo對(duì)象后,再通過(guò)下面的方法對(duì)TestInfo對(duì)象進(jìn)行注冊(cè):

GetUnitTestImpl()->AddTestInfo(set_up_tc,?tear_down_tc,?test_info);

?

GetUnitTestImpl()是獲取UnitTestImpl對(duì)象:

inline?UnitTestImpl*?GetUnitTestImpl()?{
????
return?UnitTest::GetInstance()->impl();
}

?

其中UnitTest是一個(gè)單件(Singleton),整個(gè)進(jìn)程空間只有一個(gè)實(shí)例,通過(guò)UnitTest::GetInstance()獲取單件的實(shí)例。上面的代碼看到,UnitTestImpl對(duì)象是最終是從UnitTest對(duì)象中獲取的。那么UnitTestImpl到底是一個(gè)什么樣的東西呢?可以這樣理解:

UnitTestImpl是一個(gè)在UnitTest內(nèi)部使用的,為執(zhí)行單元測(cè)試案例而提供了一系列實(shí)現(xiàn)的那么一個(gè)類。(自己歸納的,可能不準(zhǔn)確)

我們上面的AddTestInfo就是其中的一個(gè)實(shí)現(xiàn),負(fù)責(zé)注冊(cè)TestInfo實(shí)例:

?

//?添加TestInfo對(duì)象到整個(gè)單元測(cè)試中
//
//?參數(shù):
//
//???set_up_tc:??????事件函數(shù)SetUpTestCases的函數(shù)地址
//???tear_down_tc:?事件函數(shù)TearDownTestCases的函數(shù)地址
//???test_info:??????? TestInfo對(duì)象
void?AddTestInfo(Test::SetUpTestCaseFunc?set_up_tc,
???????????????Test::TearDownTestCaseFunc?tear_down_tc,
???????????????TestInfo?
*?test_info)?{
//?處理死亡測(cè)試的代碼,先不關(guān)注它
if?(original_working_dir_.IsEmpty())?{
? ? original_working_dir_.Set(FilePath::GetCurrentDir());
????
if?(original_working_dir_.IsEmpty())?{
??????? printf(
"%s\n",?"Failed?to?get?the?current?working?directory.");
??????? abort();
??? }
}
//?獲取或創(chuàng)建了一個(gè)TestCase對(duì)象,并將testinfo添加到TestCase對(duì)象中。
GetTestCase(test_info->test_case_name(),
????????????test_info
->test_case_comment(),
????????????set_up_tc,
????????????tear_down_tc)
->AddTestInfo(test_info);
}

我們看到,TestCase對(duì)象出來(lái)了,并通過(guò)AddTestInfo添加了一個(gè)TestInfo對(duì)象。這時(shí),似乎豁然開朗了:

1. TEST宏中的兩個(gè)參數(shù),第一個(gè)參數(shù)testcase_name,就是TestCase對(duì)象的名稱,第二個(gè)參數(shù)test_name就是Test對(duì)象的名稱。而TestInfo包含了一個(gè)測(cè)試案例的一系列信息。

2. 一個(gè)TestCase對(duì)象對(duì)應(yīng)一個(gè)或多個(gè)TestInfo對(duì)象。


?

我們來(lái)看看TestCase的創(chuàng)建過(guò)程(UnitTestImpl::GetTestCase):

//?查找并返回一個(gè)指定名稱的TestCase對(duì)象。如果對(duì)象不存在,則創(chuàng)建一個(gè)并返回
//
//?參數(shù):
//
//???test_case_name:??? 測(cè)試案例名稱
//???set_up_tc:????????????事件函數(shù)SetUpTestCases的函數(shù)地址
//???tear_down_tc:???????事件函數(shù)TearDownTestCases的函數(shù)地址
TestCase*?UnitTestImpl::GetTestCase(const?char*?test_case_name,
????????????????????????????????????
const?char*?comment,
????????????????????????????????????Test::SetUpTestCaseFunc?set_up_tc,
????????????????????????????????????Test::TearDownTestCaseFunc?tear_down_tc)?{
??
//?從test_cases里查找指定名稱的TestCase
? ??internal::ListNode<TestCase*>*?node?=?test_cases_.FindIf(
? ?? ?? TestCaseNameIs(test_case_name));

????
if?(node?==?NULL)?{
????????
//?沒(méi)找到,我們來(lái)創(chuàng)建一個(gè)
??????? TestCase*?const?test_case?=
?? ?????????
new?TestCase(test_case_name,?comment,?set_up_tc,?tear_down_tc);

????????
//?判斷是否為死亡測(cè)試案例
????????if?(internal::UnitTestOptions::MatchesFilter(String(test_case_name),
?????????????????????????????????????????????????kDeathTestCaseFilter))?{
????????????
//?是的話,將該案例插入到最后一個(gè)死亡測(cè)試案例后
??????????? node?=?test_cases_.InsertAfter(last_death_test_case_,?test_case);
??????????? last_death_test_case_?
=?node;
??????? }?
else?{
????????????
//?否則,添加到test_cases最后。
??????????? test_cases_.PushBack(test_case);
??????????? node?
=?test_cases_.Last();
??????? }
??? }

????
//?返回TestCase對(duì)象
????return?node->element();
}

?

三、回過(guò)頭看看TEST宏的定義

#define?TEST(test_case_name,?test_name)\
????GTEST_TEST_(test_case_name,?test_name,?\
??????????????::testing::Test,?::testing::
internal::GetTestTypeId())

?

同時(shí)也看看TEST_F宏

#define?TEST_F(test_fixture,?test_name)\
????GTEST_TEST_(test_fixture,?test_name,?test_fixture,?\
??????????????::testing::
internal::GetTypeId<test_fixture>())

都是使用了GTEST_TEST_宏,在看看這個(gè)宏如何定義的:

#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_DISALLOW_COPY_AND_ASSIGN_(\
????????GTEST_TEST_CLASS_NAME_(test_case_name,?test_name));\
};\
\
::testing::TestInfo
*?const?GTEST_TEST_CLASS_NAME_(test_case_name,?test_name)\
????::test_info_?
=\
????????::testing::
internal::MakeAndRegisterTestInfo(\
????????????#test_case_name,?#test_name,?
"",?"",?\
????????????(parent_id),?\
????????????parent_class::SetUpTestCase,?\
????????????parent_class::TearDownTestCase,?\
????????????
new?::testing::internal::TestFactoryImpl<\
????????????????GTEST_TEST_CLASS_NAME_(test_case_name,?test_name)
>);\
void?GTEST_TEST_CLASS_NAME_(test_case_name,?test_name)::TestBody()

?

不需要多解釋了,和我們上面展開看到的差不多,不過(guò)這里比較明確的看到了,我們?cè)赥EST宏里寫的就是TestBody里的東西。這里再補(bǔ)充說(shuō)明一下里面的GTEST_DISALLOW_COPY_AND_ASSIGN_宏,我們上面的例子看出,這個(gè)宏展開后:

FooTest_Demo_Test(const?FooTest_Demo_Test?&);
void?operator=(const?FooTest_Demo_Test?&);

?

正如這個(gè)宏的名字一樣,它是用于防止對(duì)對(duì)象進(jìn)行拷貝和賦值操作的。?

四、再來(lái)了解RUN_ALL_TESTS宏

我們的測(cè)試案例的運(yùn)行就是通過(guò)這個(gè)宏發(fā)起的。RUN_ALL_TEST的定義非常簡(jiǎn)單:

#define?RUN_ALL_TESTS()\
????(::testing::UnitTest::GetInstance()
->Run())

?

我們又看到了熟悉的::testing::UnitTest::GetInstance(),看來(lái)案例的執(zhí)行時(shí)從UnitTest的Run方法開始的,我提取了一些Run中的關(guān)鍵代碼,如下:

int?UnitTest::Run()?{
??? __try?{
????????
return?impl_->RunAllTests();
??? }?__except(
internal::UnitTestOptions::GTestShouldProcessSEH(
??????? GetExceptionCode()))?{
??????? printf(
"Exception?thrown?with?code?0x%x.\nFAIL\n",?GetExceptionCode());
??????? fflush(stdout);
????????
return?1;
??? }

????
return?impl_->RunAllTests();
}

?

我們又看到了熟悉的impl(UnitTestImpl),具體案例該怎么執(zhí)行,還是得靠UnitTestImpl

int?UnitTestImpl::RunAllTests()?{

????
//?...

????printer
->OnUnitTestStart(parent_);

????
//?計(jì)時(shí)
????const?TimeInMillis?start?=?GetTimeInMillis();

????printer
->OnGlobalSetUpStart(parent_);
????
//?執(zhí)行全局的SetUp事件
????environments_.ForEach(SetUpEnvironment);
????printer
->OnGlobalSetUpEnd(parent_);

????
//?全局的SetUp事件執(zhí)行成功的話
????if?(!Test::HasFatalFailure())?{
????????
//?執(zhí)行每個(gè)測(cè)試案例
????????test_cases_.ForEach(TestCase::RunTestCase);
????}

????
//?執(zhí)行全局的TearDown事件
????printer->OnGlobalTearDownStart(parent_);
????environments_in_reverse_order_.ForEach(TearDownEnvironment);
????printer
->OnGlobalTearDownEnd(parent_);

????elapsed_time_?
=?GetTimeInMillis()?-?start;

????
//?執(zhí)行完成
????printer->OnUnitTestEnd(parent_);

????
//?Gets?the?result?and?clears?it.
????if?(!Passed())?{
??????failed?
=?true;
????}
????ClearResult();

????
//?返回測(cè)試結(jié)果
????return?failed???1?:?0;
}

?

上面,我們很開心的看到了我們前面講到的全局事件的調(diào)用。environments_是一個(gè)Environment的鏈表結(jié)構(gòu)(List),它的內(nèi)容是我們?cè)趍ain中通過(guò):

testing::AddGlobalTestEnvironment(new?FooEnvironment);

?

添加進(jìn)去的。test_cases_我們之前也了解過(guò)了,是一個(gè)TestCase的鏈表結(jié)構(gòu)(List)。gtest實(shí)現(xiàn)了一個(gè)鏈表,并且提供了一個(gè)Foreach方法,迭代調(diào)用某個(gè)函數(shù),并將里面的元素作為函數(shù)的參數(shù):

template?<typename?F>??//?F?is?the?type?of?the?function/functor
void?ForEach(F?functor)?const?{
????
for?(?const?ListNode<E>?*?node?=?Head();
??????????node?
!=?NULL;
??????????node?
=?node->next()?)?{
??????functor(node
->element());
????}
}

?

因此,我們關(guān)注一下:environments_.ForEach(SetUpEnvironment),其實(shí)是迭代調(diào)用了SetUpEnvironment函數(shù):

static?void?SetUpEnvironment(Environment*?env)?{?env->SetUp();?}

?

最終調(diào)用了我們定義的SetUp()函數(shù)。

再看看test_cases_.ForEach(TestCase::RunTestCase)的TestCase::RunTestCase實(shí)現(xiàn):

static?void?RunTestCase(TestCase?*?test_case)?{?test_case->Run();?}

?

再看TestCase的Run實(shí)現(xiàn):

void?TestCase::Run()?{
????
if?(!should_run_)?return;

????
internal::UnitTestImpl*?const?impl?=?internal::GetUnitTestImpl();
????impl
->set_current_test_case(this);

????UnitTestEventListenerInterface?
*?const?result_printer?=
????impl
->result_printer();

????result_printer
->OnTestCaseStart(this);
????impl
->os_stack_trace_getter()->UponLeavingGTest();
????
//?哈!SetUpTestCases事件在這里調(diào)用
????set_up_tc_();

????
const?internal::TimeInMillis?start?=?internal::GetTimeInMillis();
????
//?嗯,前面分析的一個(gè)TestCase對(duì)應(yīng)多個(gè)TestInfo,因此,在這里迭代對(duì)TestInfo調(diào)用RunTest方法
????test_info_list_->ForEach(internal::TestInfoImpl::RunTest);
????elapsed_time_?
=?internal::GetTimeInMillis()?-?start;

????impl
->os_stack_trace_getter()->UponLeavingGTest();
????
//?TearDownTestCases事件在這里調(diào)用
????tear_down_tc_();
????result_printer
->OnTestCaseEnd(this);
????impl
->set_current_test_case(NULL);
}

第二種事件機(jī)制又浮出我們眼前,非常興奮。可以看出,SetUpTestCases和TearDownTestCaess是在一個(gè)TestCase之前和之后調(diào)用的。接著看test_info_list_->ForEach(internal::TestInfoImpl::RunTest):

static?void?RunTest(TestInfo?*?test_info)?{
????test_info
->impl()->Run();
}

哦?TestInfo也有一個(gè)impl?看來(lái)我們之前漏掉了點(diǎn)東西,和UnitTest很類似,TestInfo內(nèi)部也有一個(gè)主管各種實(shí)現(xiàn)的類,那就是TestInfoImpl,它在TestInfo的構(gòu)造函數(shù)中創(chuàng)建了出來(lái)(還記得前面講的TestInfo的創(chuàng)建過(guò)程嗎?):

TestInfo::TestInfo(const?char*?test_case_name,
???????????????????
const?char*?name,
???????????????????
const?char*?test_case_comment,
???????????????????
const?char*?comment,
???????????????????
internal::TypeId?fixture_class_id,
???????????????????
internal::TestFactoryBase*?factory)?{
????impl_?
=?new?internal::TestInfoImpl(this,?test_case_name,?name,
?????????????????????????????????????test_case_comment,?comment,
?????????????????????????????????????fixture_class_id,?factory);
}

?

因此,案例的執(zhí)行還得看TestInfoImpl的Run()方法,同樣,我簡(jiǎn)化一下,只列出關(guān)鍵部分的代碼:

void?TestInfoImpl::Run()?{

????//?...

??? UnitTestEventListenerInterface*?const?result_printer?=
??????? impl
->result_printer();
??? result_printer
->OnTestStart(parent_);
????
//?開始計(jì)時(shí)
????
const?TimeInMillis?start?=?GetTimeInMillis();

? ? Test*?test?=?NULL;

??? __try?{
????????
//?我們的對(duì)象工廠,使用CreateTest()生成Test對(duì)象
??????? test?=?factory_->CreateTest();
??? }?__except(
internal::UnitTestOptions::GTestShouldProcessSEH(
??????? GetExceptionCode()))?{
??????? AddExceptionThrownFailure(GetExceptionCode(),
??????????????????????????????
"the?test?fixture's?constructor");
????????
return;

??? }

????//?如果Test對(duì)象創(chuàng)建成功

????if?(!Test::HasFatalFailure())?{

? ? ? ??// 調(diào)用Test對(duì)象的Run()方法,執(zhí)行測(cè)試案例?

??????? test->Run();
??? }

????
//?執(zhí)行完畢,刪除Test對(duì)象
??? impl->os_stack_trace_getter()->UponLeavingGTest();
??? delete?test;
??? test?
=?NULL;

????//?停止計(jì)時(shí)
??? result_.set_elapsed_time(GetTimeInMillis()?-?start);
??? result_printer->OnTestEnd(parent_);

}

?

上面看到了我們前面講到的對(duì)象工廠fatory,通過(guò)fatory的CreateTest()方法,創(chuàng)建Test對(duì)象,然后執(zhí)行案例又是通過(guò)Test對(duì)象的Run()方法:

void?Test::Run()?{
????
if?(!HasSameFixtureClass())?return;

????
internal::UnitTestImpl*?const?impl?=?internal::GetUnitTestImpl();
????impl
->os_stack_trace_getter()->UponLeavingGTest();
????__try?{
????????
//?Yeah!每個(gè)案例的SetUp事件在這里調(diào)用
????????SetUp();
????}?__except(
internal::UnitTestOptions::GTestShouldProcessSEH(
????????GetExceptionCode()))?{
????????AddExceptionThrownFailure(GetExceptionCode(),?
"SetUp()");
????}

????
//?We?will?run?the?test?only?if?SetUp()?had?no?fatal?failure.
????if?(!HasFatalFailure())?{
????????impl
->os_stack_trace_getter()->UponLeavingGTest();
????????__try?{
????????????
//?哈哈!!千辛萬(wàn)苦,我們定義在TEST宏里的東西終于被調(diào)用了!
????????????TestBody();
????????}?__except(
internal::UnitTestOptions::GTestShouldProcessSEH(
????????????GetExceptionCode()))?{
????????????AddExceptionThrownFailure(GetExceptionCode(),?
"the?test?body");
????????}
????}

????impl
->os_stack_trace_getter()->UponLeavingGTest();
????__try?{
????????
//?每個(gè)案例的TearDown事件在這里調(diào)用
????????TearDown();
????}?__except(
internal::UnitTestOptions::GTestShouldProcessSEH(
????????GetExceptionCode()))?{
????????AddExceptionThrownFailure(GetExceptionCode(),?
"TearDown()");
????}
}

?

上面的代碼里非常極其以及特別的興奮的看到了執(zhí)行測(cè)試案例的前后事件,測(cè)試案例執(zhí)行TestBody()的代碼。仿佛整個(gè)gtest的流程在眼前一目了然了。

四、總結(jié)

本文通過(guò)分析TEST宏和RUN_ALL_TEST宏,了解到了整個(gè)gtest運(yùn)作過(guò)程,可以說(shuō)整個(gè)過(guò)程簡(jiǎn)潔而優(yōu)美。之前讀《代碼之美》,感觸頗深,現(xiàn)在讀過(guò)gtest代碼,再次讓我感觸深刻。記得很早前,我對(duì)設(shè)計(jì)的理解是“功能越強(qiáng)大越好,設(shè)計(jì)越復(fù)雜越好,那樣才顯得牛”,漸漸得,我才發(fā)現(xiàn),簡(jiǎn)單才是最好。我曾總結(jié)過(guò)自己寫代碼的設(shè)計(jì)原則:功能明確,設(shè)計(jì)簡(jiǎn)單。了解了gtest代碼后,猛然發(fā)現(xiàn)gtest不就是這樣嗎,同時(shí)gtest也給了我很多驚喜,因此,我對(duì)gtest的評(píng)價(jià)是:功能強(qiáng)大,設(shè)計(jì)簡(jiǎn)單,使用方便

總結(jié)一下gtest里的幾個(gè)關(guān)鍵的對(duì)象:

1. UnitTest 單例,總管整個(gè)測(cè)試,包括測(cè)試環(huán)境信息,當(dāng)前執(zhí)行狀態(tài)等等。

2. UnitTestImpl UnitTest內(nèi)部具體功能的實(shí)現(xiàn)者。

3. Test ?? 我們自己編寫的,或通過(guò)TEST,TEST_F等宏展開后的Test對(duì)象,管理著測(cè)試案例的前后事件,具體的執(zhí)行代碼TestBody。

4. TestCase 測(cè)試案例對(duì)象,管理著基于TestCase的前后事件,管理內(nèi)部多個(gè)TestInfo。

5. TestInfo? 管理著測(cè)試案例的基本信息,包括Test對(duì)象的創(chuàng)建方法。?

6. TestInfoImpl TestInfo內(nèi)部具體功能的實(shí)現(xiàn)者 。

本文還有很多gtest的細(xì)節(jié)沒(méi)有分析到,比如運(yùn)行參數(shù),死亡測(cè)試,跨平臺(tái)處理,斷言的宏等等,希望讀者自己把源碼下載下來(lái)慢慢研究。如本文有錯(cuò)誤之處,也請(qǐng)大家指出,謝謝!

超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。