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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Gooogle Test中的TEST()宏代码分析

發布時間:2025/3/14 编程问答 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Gooogle Test中的TEST()宏代码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Primer文檔中了解到,一般情況下,在TEST()宏定義一個自己的測試案例,第一部分為單元測試名字,第二部分為測試名。那么TEST()宏的原定義是一個什么樣的形式的呢?為什么只需要定義TEST()宏就可以了呢,這里面有什么技巧嗎?作為一個技術員,雖然只需要接口就能夠編寫應用程序,然而如果能夠獲取內部更多信息,那么我們將會編寫的更加完美的程序,編寫的程序更加有效。那么下面我們就慢慢開始解剖TEST()宏。

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

?

gtest/gtest.h頭文件中,可以找到TEST()宏的定義:


?#define?TEST(test_case_name,?test_name)\
??GTEST_TEST(test_case_name,?test_name,?::testing::Test)

也是就是TEST()宏是通過GTEST_TEST宏來實現的,也就是TEST()宏將用GTEST_TEST()來替代。那么既然想要刨根問底,我們就要知道GTEST_TEST()是怎么實現的,我在gtest.h頭文件通過查找方式怎么也找不到GTEST_TEST()宏,那么該文件在哪兒呢?

?

Primer并沒有提示我們在外部使用GTEST_TEST(),這也就是說GTEST_TEST()應該是內部使用的,否則也不用TEST在來包裝一下的。查看gtest目錄后斷定應該在gtest-internal.h文件中,打開gtest-internal.h文件,查找搜索了一下,嘿嘿,果真在里面有GTEST_TEST()宏,該宏的實現如下(注意不要忽略了\符號):

?

//?Helper?macro?for?defining?tests.
#define?GTEST_TEST(test_case_name,?test_name,?parent_class)\
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,?
"",?"",?\
????????::testing::
internal::GetTypeId<?parent_class?>(),?\
????????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()
?

從上面可以看到GTEST_TEST申明了一個類,該類派生自parent_class,類含有一個靜態成員變量指針,從TEST宏定義中知道在外部定義TEST()將獲取一個從::testing::Test中派生的類申明,類名字為

GTEST_TEST_CLASS_NAME_(test_case_name, test_name),讓我們把眼睛往上面瞄一瞄,原來類名字是那么定義的:

//?Expands?to?the?name?of?the?class?that?implements?the?given?test.
#define?GTEST_TEST_CLASS_NAME_(test_case_name,?test_name)?\
??test_case_name##_##test_name##_Test

?

##表示鏈接前后字符為字符串。如果我們定義的TEST(FactorialTest, Zero),將會得到一個FactorialTest_Zero_Test的類名。

?

GoogleTestPrimer中宏是被這么定義的:

//?Tests?factorial?of?0.
TEST(FactorialTest,?Zero)?{
??EXPECT_EQ(
1,?Factorial(0))
}

?

很少看到宏定義后面還能與函數類似的,帶個括號還能夠編寫任何語句,通過上面的代碼就清楚了,{}中的內容是成員虛擬函數的內容

?

TEST(FactorialTest,?Zero)
{
????EXPECT_EQ(
1,?Factorial(0));
}


宏定義擴展將得到:

?

FactorialTest_Zero_Test
class?FactorialTest_Zero_Test?:?public?::testing::Test
{
public:
?????????FactorialTest_Zero_Test()?{}
private:
?????????
virtual?void?TestBody();
?????????
static?::testing::TestInfo*?const?test_Info_;
?????????GTEST_DISALLOW_COPY_AND_ASSIGN(?FactorialTest_Zero_Test??);
};

::testing::TestInfo
*?const?FactorialTest_Zero_Test::test_Info_?=
?::testing::
internal::MakeAndRegisterTestInfo(?FactorialTest,?Zero,?“”,?“”,?\
?????????::testing::
internal::GetTypeId<::testing::Test>(),
?????????::testing::Test::SetUpTestCase,
?????????::testing::Test::TearDownTestCase,
?????????
new?::testing::internal::TestFactoryImpl<?FactorialTest_Zero_Test>?);
void?GTEST_TEST_CLASS_NAME_(test_case_name,?test_name)::TestBody()
{
??EXPECT_EQ(
1,?Factorial(0));
}

我們一步步來分析,這個類很簡單,一個默認的構造函數實現,一個虛擬函數聲明,一個靜態變量聲明,一個未知的宏GTEST_DISALLOW_COPY_AND_ASSIGN。默認構造函數就不必多說了。先來看虛擬函數,底部的擴展將虛擬函數的實現擴展出來了,前面分析說過,宏TEST()中的內容是虛擬函數中的內容,也就是我們是實現的是虛擬函數TestBody的內容。依據一般的思想,測試內部通過模板設計模式思想來調用該虛擬函數,從而達到TestBody被執行,那么內部如何知道新設計的類呢?那么就需要靜態變量testInfo或未知宏來說明了,testInfo通過內部函數MakeAndRegisterTestInfo()調用來實現其指針的賦值。MakeAndRegisterTestInfo()原型如下:


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);

參數說明:

?? test_case_name:?? ???????? ?測試案例名稱

? name:?? ??????????測試名稱

?? test_case_comment: 測試案例注釋,將在測試輸出中包含

?? comment:????????? 測試注釋,將在測試輸出中包含

?? fixture_class_id: ????test fixture類的ID

?? set_up_tc:??????? ??指向構建測試案例的函數指針

?? tear_down_tc:???? 指向銷毀測試案例的函數指

?? factory:????????? 指向創建測試對象的工廠對象,新創建的TestInfo實例假定屬于工廠對象

?

顯然前面四個參數毋庸過多的解釋,第五個參數test fixtureID,實現的非常有技巧:

Code
template?<typename?T>
inline?TypeId?GetTypeId()?{
??
static?bool?dummy?=?false;
??
//?The?compiler?is?required?to?create?an?instance?of?the?static
??
//?variable?dummy?for?each?T?used?to?instantiate?the?template.
??
//?Therefore,?the?address?of?dummy?is?guaranteed?to?be?unique.
??return?&dummy;
}


利用編譯器只為模板生成一個對象實例,相同類(

T)僅有一個GetTypeId()函數,而不同類的GetTypeId()函數是不同的,從而,相同的函數具有相同的dummy地址,不同的函數dummy地址不同,從而實現了類的id唯一。沒錯,代碼很簡單,但實現的非常perfect。真正應了一句,簡單才是最好的!

?

函數地址的指針的賦值實現就相當貴簡單了一些,通過傳遞兩個靜態實現函數即可,如果需要自己的函數實現,依據Primer教程實現即可!此處暫不分析這部分內容。

?

最后一個是工廠類,顯然工廠需要能夠生成自定義類,但是工廠并不知道我們定義了什么樣的類?那么Google Test是如何使實現的呢,代碼是最好的老師:


?//?This?class?provides?implementation?of?TeastFactoryBase?interface.該類實現了TestFactoryBase接口
//?It?is?used?in?TEST?and?TEST_F?macros.?在TEST和TEST_F宏中被實現
template?<class?TestClass>
class?:?public?TestFactoryBase?{
?
public:
??
virtual?Test*?CreateTest()?{?return?new?TestClass;?}
};

?


沒錯,通過模板,新建一個自定義對象,通過虛擬函數返回一個基類的指針,這樣
TestFactoryBase就可以控制生成的對象了!

?

我們通過new TestFactoryImpl來得到TestFactoryImpl的實例傳遞給MakeAndRegisterTestInfo函數,從而實現內部的工廠類管理。內部得到工廠類后調用其虛擬函數CreateTest方法,創建一個新的自定義對象,并管理該對象,由于自定義對象覆蓋了其基類的TestBody方法,因此可以通過獲得的自定義對象來調用TestBody方法,從而實現了自動測試的目的。

?

上面一段的內容均是猜測,是否如此,我們下回一起分析ALL_TEST_RUNS()宏,看看究竟是否如此。

?

TEST_F()宏的實現與TEST類類似,也在下回一起分析吧。

?

總結一下:

?? TEST()宏先擴展成GTEST_TEST()宏,然后GTEST_TEST()宏組裝自定義類名字,聲明(派生自::testing::Test類)以及部分實現,虛擬函數TestBodyTEST()宏擴展補充實現。在類定義過程中使用模板工廠方法,創建自定義類對象,從而使得內部可以管理自定義類,最終實現測試自動化。

?

其中兩個技巧非常不錯:

1、通過地址唯一性來獲取類ID的唯一性,并且用到了編譯器的特性。

template?<typename?T>
inline?TypeId?GetTypeId()?{
??
static?bool?dummy?=?false;
??
return?&dummy;
}


2

、通過覆蓋基類方法,創建自定義類的實例,采用模板方法,使得實例創建更加簡潔,無需更多的Factory類。

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

?

轉載于:https://www.cnblogs.com/ubunoon/archive/2008/11/08/GoogleTestTestAnalysis.html

總結

以上是生活随笔為你收集整理的Gooogle Test中的TEST()宏代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。