7深入分析gtestWord格式文档下载.docx
《7深入分析gtestWord格式文档下载.docx》由会员分享,可在线阅读,更多相关《7深入分析gtestWord格式文档下载.docx(12页珍藏版)》请在冰豆网上搜索。
FooTest_Demo_Test(const
&
);
operator=(const
};
test_info_
=
internal:
MakeAndRegisterTestInfo(
"
FooTest"
Demo"
(:
GetTestTypeId()),
Test:
SetUpTestCase,
TearDownTestCase,
new
TestFactoryImpl<
FooTest_Demo_Test>
FooTest_Demo_Test:
TestBody()
switch
(0)
case
0:
if
(const
AssertionResult
gtest_ar
EqHelper<
(sizeof(:
IsNullLiteralHelper
(1))
==
1)>
Compare("
1"
1,
1)))
;
else
AssertHelper(
TPRT_NONFATAL_FAILURE,
.\\gtest_demo.cpp"
9,
gtest_ar.failure_message()
)
Message();
展开后,我们观察到:
1.TEST宏展开后,是一个继承自testing:
Test的类。
2.我们在TEST宏里面写的测试代码,其实是被放到了类的TestBody方法中。
3.通过静态变量test_info_,调用MakeAndRegisterTestInfo对测试案例进行注册。
如下图:
上面关键的方法就是MakeAndRegisterTestInfo了,我们跳到MakeAndRegisterTestInfo函数中:
//
创建一个
TestInfo
对象并注册到
Google
Test;
返回创建的TestInfo对象
//
参数:
test_case_name:
测试案例的名称
name:
测试的名称
test_case_comment:
测试案例的注释信息
comment:
测试的注释信息
fixture_class_id:
testfixture类的ID
set_up_tc:
事件函数SetUpTestCases的函数地址
tear_down_tc:
事件函数TearDownTestCases的函数地址
factory:
工厂对象,用于创建测试对象(Test)
MakeAndRegisterTestInfo(
char*
test_case_name,
name,
test_case_comment,
comment,
TypeId
fixture_class_id,
SetUpTestCaseFunc
set_up_tc,
TearDownTestCaseFunc
tear_down_tc,
TestFactoryBase*
factory)
test_info
=
TestInfo(test_case_name,
name,
fixture_class_id,
factory);
GetUnitTestImpl()->
AddTestInfo(set_up_tc,
tear_down_tc,
test_info);
return
test_info;
我们看到,上面创建了一个TestInfo对象,然后通过AddTestInfo注册了这个对象。
TestInfo对象到底是一个什么样的东西呢?
TestInfo对象主要用于包含如下信息:
1.测试案例名称(testcasename)
2.测试名称(testname)
3.该案例是否需要执行
4.执行案例时,用于创建Test对象的函数指针
5.测试结果
我们还看到,TestInfo的构造函数中,非常重要的一个参数就是工厂对象,它主要负责在运行测试案例时创建出Test对象。
我们看到我们上面的例子的factory为:
我们明白了,Test对象原来就是TEST宏展开后的那个类的对象(FooTest_Demo_Test),再看看TestFactoryImpl的实现:
template
<
TestClass>
TestFactoryImpl
TestFactoryBase
Test*
CreateTest()
{
TestClass;
这个对象工厂够简单吧,嗯,Simpleisbetter。
当我们需要创建一个测试对象(Test)时,调用factory的CreateTest()方法就可以了。
创建了TestInfo对象后,再通过下面的方法对TestInfo对象进行注册:
GetUnitTestImpl()是获取UnitTestImpl对象:
inline
UnitTestImpl*
GetUnitTestImpl()
UnitTest:
GetInstance()->
impl();
其中UnitTest是一个单件(Singleton),整个进程空间只有一个实例,通过UnitTest:
GetInstance()获取单件的实例。
上面的代码看到,UnitTestImpl对象是最终是从UnitTest对象中获取的。
那么UnitTestImpl到底是一个什么样的东西呢?
可以这样理解:
UnitTestImpl是一个在UnitTest内部使用的,为执行单元测试案例而提供了一系列实现的那么一个类。
(自己归纳的,可能不准确)
我们上面的AddTestInfo就是其中的一个实现,负责注册TestInfo实例:
添加TestInfo对象到整个单元测试中
test_info:
TestInfo对象
AddTestInfo(Test:
*
test_info)
处理死亡测试的代码,先不关注它
(original_working_dir_.IsEmpty())
original_working_dir_.Set(FilePath:
GetCurrentDir());
if
printf("
%s\n"
Failed
to
get
the
current
working
directory."
abort();
}
获取或创建了一个TestCase对象,并将testinfo添加到TestCase对象中。
GetTestCase(test_info->
test_case_name(),
test_info->
test_case_comment(),
tear_down_tc)->
AddTestInfo(test_info);
我们看到,TestCase对象出来了,并通过AddTestInfo添加了一个TestInfo对象。
这时,似乎豁然开朗了:
1.TEST宏中的两个参数,第一个参数testcase_name,就是TestCase对象的名称,第二个参数test_name就是Test对象的名称。
而TestInfo包含了一个测试案例的一系列信息。
2.一个TestCase对象对应一个或多个TestInfo对象。
我们来看看TestCase的创建过程(UnitTestImpl:
GetTestCase):
//查找并返回一个指定名称的TestCase对象。
如果对象不存在,则创建一个并返回
//参数:
测试案例名称
TestCase*
UnitTestImpl:
GetTestCase(const
test_case_name,
tear_down_tc)
//从test_cases里查找指定名称的TestCase
internal:
ListNode<
TestCase*>
node
test_cases_.FindIf(
TestCaseNameIs(test_case_name));
(node
NULL)
//没找到,我们来创建一个
TestCase*
test_case
new
TestCase(test_case_name,
comment,
set_up_tc,
tear_down_tc);
//判断是否为死亡测试案例
(internal:
UnitTestOptions:
MatchesFilter(String(test_case_name),
kDeathTestCaseFilter))
//是的话,将该案例插入到最后一个死亡测试案例后
node
test_cases_.InsertAfter(last_death_test_case_,
test_case);
last_death_test_case_
node;
}
//否则,添加到test_cases最后。
test_cases_.PushBack(test_case);
test_cases_.Last();
//返回TestCase对象
return
node->
element();
三、回过头看看TEST宏的定义
#define
TEST(test_case_name,
test_name)\
GTEST_TEST_(test_case_name,
test_name,
\
Test,
GetTestTypeId())
同时也看看TEST_F宏
TEST_F(test_fixture,
GTEST_TEST_(test_fixture,
test_fixture,
GetTypeId<
test_fixture>
())
都是使用了GTEST_TEST_宏,在看看这个宏如何定义的:
parent_class,
parent_id)\
GTEST_TEST_CLASS_NAME_(test_case_name,
test_name)
parent_class
{\
test_name)()
{}\
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
test_name));
=\
MakeAndRegisterTestInfo(\
#test_case_name,
#test_name,
(parent_id),
parent_class:
SetUpTestCase,
TearDownTestCase,
test_name)>
test_name):
不需要多解释了,和我们上面展开看到的差不多,不过这里比较明确的看到了,我们在TEST宏里写的就是TestBody里的东西。
这里再补充说明一下里面的GTEST_DISALLOW_COPY_AND_ASSIGN_宏,我们上面的例子看出,这个宏展开后:
正如这个宏的名字一样,它是用于防止对对象进行拷贝和赋值操作的。
四、再来了解RUN_ALL_TESTS宏
我们的测试案例的运行就是通过这个宏发起的。
RUN_ALL_TEST的定义非常简单:
RUN_ALL_TESTS()\
Run())
我们又看到了熟悉的:
GetInstance(),看来案例的执行时从UnitTest的Run方法开始的,我提取了一些Run中的关键代码,如下:
int
Run()
__try
impl_->
RunAllTests();
__except(internal:
GTestShouldProcessSEH(
GetExceptionCode()))
Exception
thrown
with
code
0x%x.\nFAIL\n"
GetExceptionCode());
fflush(stdout);
1;
我们又看到了熟悉的impl(UnitTestImpl),具体案例该怎么执行,还是得靠UnitTestImpl。
RunAllTests()
//...
printer->
OnUnitTestStart(parent_);
计时
TimeInMillis
start
GetTimeInMillis();
OnGlobalSetUpStart(parent_);
执行全局的SetUp事件
environments_.ForEach(SetUpEnvironment);
OnGlobalSetUpEnd(parent_);
全局的SetUp事件执行成功的话
(!
HasFatalFailure())
执行每个测试案例
test_cases_.ForEach(TestCase:
RunTestCase);
执行全局的TearDown事件
OnGlobalTearDownStart(parent_);
environments_in_reverse_order_.ForEach(TearDownEnvironment);
OnGlobalTearDownEnd(parent_);
elapsed_time_
GetTimeInMillis()
-
start;
执行完成
OnUnitTestEnd(parent_);
Gets
result
and
clears
it.
Passed())
failed
true;
ClearResult();
返回测试结果
?
1
0;
上面,我们很开心的看到了我们前面讲到的全局事件的调用。
environments_是一个Environment的链表结构(List),它的内容是我们在main中通过:
AddGlobalTestEnvironment(new
FooEnvironment);
添加进去的。
test_cases_我们之前也了解过了,是一个TestCase的链表结构(List)。
gtest实现了一个链表,并且提供了一个Foreach方法,迭代调用某个函数,并将里面的元素作为函数的参数:
typename
F>
F
is
type
of
fu