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()宏,该宏的实现如下(注意不要忽略了\符号):
#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),让我们把眼睛往上面瞄一瞄,原来类名字是那么定义的:
#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))
}
很少看到宏定义后面还能与函数类似的,带个括号还能够编写任何语句,通过上面的代码就清楚了,{}中的内容是成员虚拟函数的内容
将
{
EXPECT_EQ(1, Factorial(0));
}
宏定义扩展将得到:
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 fixture的ID,实现的非常有技巧:
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类)以及部分实现,虚拟函数TestBody由TEST()宏扩展补充实现。在类定义过程中使用模板工厂方法,创建自定义类对象,从而使得内部可以管理自定义类,最终实现测试自动化。
其中两个技巧非常不错:
1、通过地址唯一性来获取类ID的唯一性,并且用到了编译器的特性。
inline TypeId GetTypeId() {
static bool dummy = false;
return &dummy;
}
2
、通过覆盖基类方法,创建自定义类的实例,采用模板方法,使得实例创建更加简洁,无需更多的Factory类。
class : public TestFactoryBase {
public:
virtual Test* CreateTest() { return new TestClass; }
};
转载于:https://www.cnblogs.com/ubunoon/archive/2008/11/08/GoogleTestTestAnalysis.html
Gooogle Test中的TEST()宏代码分析相关推荐
- python3颜色代码_python3中布局背景颜色代码分析
我们想要给某个模块着重突出,以便引起大家注意的时候,通常给那个模块的背景颜色换亮一点.这种情况的操作多见于我们想要突出表格中的某个数据,或是某一项的名称. 在python3中设置布局背景颜色需要通过代 ...
- python背景颜色代码大全_python3中布局背景颜色代码分析
我们想要给某个模块着重突出,以便引起大家注意的时候,通常给那个模块的背景颜色换亮一点.这种情况的操作多见于我们想要突出表格中的某个数据,或是某一项的名称. 在python3中设置布局背景颜色需要通过代 ...
- vins中imu融合_VINS-Mono代码分析与总结(最终版)
VINS-Mono代码分析总结 参考文献 前言 ??视觉与IMU融合的分类: 松耦合和紧耦合:按照是否把图像的Feature加入到状态向量区分,换句话说就是松耦合是在视觉和IMU各自求出的位姿的基础上 ...
- uboot中关于LCD的代码分析
以下内容源于朱有鹏<物联网大讲坛>课程的学习,如有侵权,请告知删除. 1.在uboot-jiuding/board.c中,init_sequence中的display_banner中的op ...
- 利用DOCX文档远程模板注入执行宏代码
利用DOCX文档远程模板注入执行宏代码 简介 本地文件中在没有宏代码的情况下,攻击者可以尝试执行远程文件中宏代码.其中来自APT28的最新样本将此技术展现的淋漓尽致.该样本是docx文件,文件内没有任 ...
- 内核RDMA模块(siw)代码分析
siw是内核中实现的RDMA设备驱动模块.与其他RDMA设备驱动不同的是,这个模块没有对应的硬件设备,而是通过软件方式模拟了一个使用iWARP协议的RDMA设备,通过内核的socket接口完成tcp报 ...
- Macro_Pack中的宏代码混淆方法分析
宏混淆工具 Macro_Pack是一个用于自动化混淆及生成Office文档.VB脚本.快捷方式等文件的工具,其主要用于渗透测试.demo以及社会工程学评估.macro_pack的目标是简化利用流程,反 ...
- Nature子刊:宏基因组中挖掘原核基因组的分析流程
宏基因组中挖掘原核基因组的分析流程 从宿主相关的短读长鸟枪宏基因组测序数据中恢复原核基因组 Recovering prokaryotic genomes from host-associated, s ...
- linux内核中链表代码分析---list.h头文件分析(二)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...
最新文章
- 用matlab自己搭建bp神经网络,怎样在matlab里建立一个BP神经网络模型?
- java socket相关的timeout
- Chrome 扩展 最近的历史 HistoryBar v1.1
- Linxu入门(一)
- Spring Cloud Hystrix——熔断器
- libsvm3.22——在matlab(32位和64位)中的安装
- 光栅衍射C语言程序,基于matcom的光栅衍射仿真程序
- Android版式– LinearLayout,RelativeLayout
- linux抓包工具:tcpdump 工具用法
- C ++入门系列博客一 最初的起点 — Hello World
- if语句、逻辑表达式、运算符
- [黑科技] 使用Word和Excel自制题库自判断答题系统
- 思维导图——线性代数知识点总结
- ps多种去水印方法与技巧-适合各种水印
- 左神算法中级班第三课[C++代码]
- 分治法求循环赛日程表
- 湿度控制c语言程序,基于51单片机的湿度控制系统设计.doc
- [应用笔记] HTU21D(HTU20/SHT21/SHT20)温湿度传感器常见问题
- 性能监控之linux sar命令
- android 获取usb serialnumber,iOS9获取手机序列号serialNumber(UDID)
热门文章
- 开机启动脚本/etc/init.d/rcS
- BINDER SECCTX PATCH ANALYSIS
- 一文读懂区块链上的隐私与监管问题
- Android安全教程(3)---Fiddler简易使用教程之抓取https包
- BZOJ 2038: [2009国家集训队]小Z的袜子(莫队算法例题)
- android 默认开关,android默认设置的开关
- cadence 常见pcb电阻_经验分享|高频PCB设计中出现的干扰分析及对策
- python软件开发文档目录_python学习之-软件开发的目录规范
- 构架、框架、设计模式之间的关系简述
- ECCV 2012 KCF/DCF:《High-speed tracking with kernelized correlation filters》论文笔记