Gooogle 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的類名。
?
在GoogleTest的Primer中宏是被這么定義的:
//?Tests?factorial?of?0.
TEST(FactorialTest,?Zero)?{
??EXPECT_EQ(1,?Factorial(0))
}
?
很少看到宏定義后面還能與函數類似的,帶個括號還能夠編寫任何語句,通過上面的代碼就清楚了,{}中的內容是成員虛擬函數的內容
?
將
TEST(FactorialTest,?Zero)
{
????EXPECT_EQ(1,?Factorial(0));
}
宏定義擴展將得到:
?
FactorialTest_Zero_Testclass?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 fixture的ID,實現的非常有技巧:
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;
}
利用編譯器只為模板生成一個對象實例,相同類(
?
函數地址的指針的賦值實現就相當貴簡單了一些,通過傳遞兩個靜態實現函數即可,如果需要自己的函數實現,依據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就可以控制生成的對象了!
?
?
上面一段的內容均是猜測,是否如此,我們下回一起分析ALL_TEST_RUNS()宏,看看究竟是否如此。
?
TEST_F()宏的實現與TEST類類似,也在下回一起分析吧。
?
總結一下:
?? TEST()宏先擴展成GTEST_TEST()宏,然后GTEST_TEST()宏組裝自定義類名字,聲明(派生自::testing::Test類)以及部分實現,虛擬函數TestBody由TEST()宏擴展補充實現。在類定義過程中使用模板工廠方法,創建自定義類對象,從而使得內部可以管理自定義類,最終實現測試自動化。
?
其中兩個技巧非常不錯:
1、通過地址唯一性來獲取類ID的唯一性,并且用到了編譯器的特性。
template?<typename?T>
inline?TypeId?GetTypeId()?{
??static?bool?dummy?=?false;
??return?&dummy;
}
2
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()宏代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何避免安装SQL2005的COM+错误
- 下一篇: Dynamics CRMのアップデートイ