Gtest是google推出的C++测试框架,本篇文档,从整体上对Gtest的运行过程中的关键路径进行分析和梳理。

分析入口

新建一个最简单的测试工程,取名为source_analyse_proj,建立一个简单的测试案例,为了便于分析,可以利用预编译处理器生成经过预编译的文件,来理解复杂宏。具体到VS环境中,进行如下设置:

生成项目,就可以找到对应的main.i预编译处理文件.如果需要生产obj文件,这里面的设置需要都修改为否

整体概览

从使用上,gtest可以看成是由各种不同的TEST宏组合成测试案例,再由RUN_ALL_TESTS()宏来执行各个不同的测试案例,下面来依次分析。

源码:

实际上定义了一个FooTest_HandleNoneZeroInput_Test的类:

可以看出,实际定义的类名称为“测试案例名称_测试名称_Test”,继承于 ::testing::Test类,里面有一个TestBody虚函数,可以猜想到测试框架在具体执行时,肯定是通过TestBody接口去执行各个不同测试案例中的测试函数。

每一个测试案例中都定义了一个静态成员指针,肯定是要在外部进行初始化操作的,这个操作留到下面去讲解。后面两句就是简单的拷贝构造函数和赋值构造函数,这里是为了不允许这两项操作,因此定义为private成员函数.

下面来讨论 test_info_成员,它的初始化时这样的:

利用::testing::internal的全局函数MakeAndRegisterTestInfo来实现初始化,因为它返回的是一个指针,所以可以想到这个函数应该是返回了一个new出来的指针.这里的最后一个输入参数为 new出来的模板实例, TestFactoryImpl提供了创建对应实例的接口,上面的TEST定义了一个类,在这里,生成这个类的模板实例,该类的实例生成需要等到后续执行过程中才会生成,每个测试实例的父类都是::testing::Test

MakeAndRegisterTestInfo的具体实现就下面两句:

这里面,要小析一下GetUnitTestImpl的实现,经过查阅,得知这里是一种将接口定义和细节实现分离的方式,获取主要整理细节代码如下:

UnitTest类中全部成员函数的实现,都是调用UnitTestImpl来实现的,在这里UnitTestImpl是实现,UnitTest是接口,两者之间相互隔离,接口隐藏底层实现细节

好了,我们回到正题,AddTestInfo从名字上面来看,意义应该是增加测试用例信息,这样的用例信息肯定有很多个,UnitTestImpl使用了

来保存每个TestCase信息,每一种TestCase下面可以含有多个测试子用例,所以在TestCase里面,用test_info_list_来保存同属于一个测试用例下面的测试子用例

这上面的一切操作,都是在初始化静态指针成员变量时完成的。

执行所有测试用例

测试框架启动代码,首选接管命令行输入,以便gtest可以通过额外的参数来控制测试流程。

然后调用RUN_ALL_TEST(),运行所有测试用例

这里通过UnitTest::Run进入,然后进入到UnitTestImpl::RunAllTests函数中,为这么这样设计,而不是一开始就进入RunAllTests函数中去呢?这里,gtest考虑到在测试程序执行中,可能会出现一些异常情况,而某些异常可能会导致整个测试进程退出,因此,在UnitTest::Run中,对各个适配平台的异常处理做了设置,确保这些异常不会终止程序,而是被准确记录下来。

测试案例执行流程,移除不相关代码

中间的循环依次执行TestInfo的Run函数,

这里面先会调用TestFactoryBase::CreateTest,这个是通用的虚函数,用于真实new出来测试用例的实例,每一个测试子案例都是派生自::testing::Test类,执行完对应的Run函数后,会通过Test::DeleteSelf_来释放掉对应的控件。Test类的Run函数简化后如下:

依次调用SetUp、TestBody和TearDown函数,其中,TestBody就是我们在TEST宏中真实定义的函数.这里,Gtest用到了特殊的方法来定位TestBody和实际代码入口,从预编译的结果上来看,应该是记录了TEST()宏后面测试语句的所在行号,在实际运行过程中,找到根据这个行号,找到对应的入口地址,然后去执行.具体原理,尚不清楚。

数据共享

全局测试数据共享,可以通过继承testing::Environment得到环境子类,在此子类中定义全局共享数据,在SetUp/TearDown虚函数中进行对应的初始化,启动时将此环境子类添加到全局环境中,就可在每个测试案例中使用。【这种方式,可能会破坏各个测试实例之间的独立性,不建议使用】

测试案例级别数据共享,可以通过继承testing::Test得到测试用例,在此子类中定义静态成员变量,在SetUpTestCase/TearDownTestCase虚函数中进行对应初始化,使用TEST_F来进行测试用例的声明,即可共享数据

 

参考链接:

http://www.cnblogs.com/jycboy/p/AdvancedGuide2.html

http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html

gtest运行小析的更多相关文章

  1. Poco logger 日志使用小析

    Poco logger 日志使用小析 Poco logger 日志使用小析 日志 logger 库选择 Pocologger 架构简析 步骤一 生成消息 步骤二 写入logger 步骤三 导入chan ...

  2. JLink 软件复位、Halt及运行小工具

    调试硬件时常常需要复位目标芯片,每次断电上电太麻烦,又不喜欢总打开segger的命令行,于是就搞了这个小工具:   QT绿色软件,解压即可运行,打开JLinkRST.exe,点击Connect即可通过 ...

  3. hadoop之HDFS运行小观察

    hadoop 是当前很火的一个  大数据运行框架和平台, 对于这个神奇的大家伙我甚是搞不清楚,前段时间闲来无视便把 HADOOP 运行起来, 看着它的操作记录存储部分(操作日志), IMAGE 记录着 ...

  4. js回调函数,字符串,数组小析

    (一)回调函数:是指通过函数参数传递到其他代码的,某一块可执行代码的引用.这一设计允许了底层代码调用在高层定义的子程序.在抖动函数中,回调函数用于在实现一些功能之后采取的另外的措施,比如div,照片抖 ...

  5. ArcGIS Earth数据小析

    ArcGIS Earth,一款轻量级的三维地球应用.因为工作关系下载试用了半天,正好借这个机会简单研究一下ArcGIS Earth的大概思路,特别是地形数据的组成和影像数据的加载,在这总结整理一下.下 ...

  6. javaIO框架小析

    IO即数据读写.数据是应用的中心要素,而数据读写的能力和可扩展性是编程平台的基础支撑. 概念框架 方式: 字节流 Byte 和 字符流 Char 方向: 输入 Input 和 输出 Output : ...

  7. android GC内存回收小析

    由于时间问题,简单的谈谈自己的理解. 大家都知道,在android开发中,不需要自己去管理,有垃圾回收机制会自动帮我们去回收 没有被引用到的对象. 那垃圾回收机制到底是怎样的呢?下面列出本人的一些理解 ...

  8. vivado第一天从建立文件运行小程序开始

    今天,是第一天什么也处于懵懂的时候,首要的任务就是建立一个文件 首先打开vivado运行软件, 如图所示,选择第一个create new project 来新建文件 选择存储路径,一路向下 当选择芯片 ...

  9. ASP.NET 异步Web API + jQuery Ajax 文件上传代码小析

    该示例中实际上应用了 jquery ajax(web client) + async web api 双异步. jquery ajax post $.ajax({ type: "POST&q ...

随机推荐

  1. 纯CSS3打造非常炫的加载动画

    纯css3打造的一款非常炫的加载图.用在需要一定时间加载的地方非常合适.先上效果图: 点击这里在线预览 代码非常简单.没有用任何javascript代码.纯css3实现. html代码: <di ...

  2. mysql处理varchar类型的between和and的时间问题少一天解决;

    select * from table where CJSJ day),"%Y-%m-%d") 数据库中的时间类型是varchar,传入的类型也是string 上述sql的意思是: ...

  3. java基础篇---网络编程(TCP程序设计)

    TCP程序设计 在Java中使用Socket(即套接字)完成TCP程序的开发,使用此类可以方便的建立可靠地,双向的,持续的,点对点的通讯连接. 在Socket的程序开发中,服务器端使用serverSo ...

  4. plot sin 动态配置rc settings

    plot sin 动态配置rc settings 坐标轴颜色 线的颜色 绘图前景色 Code #!/usr/bin/env python # -*- coding: utf-8 -*- import ...

  5. Postgresql查询表的大小

    --数据库中单个表的大小(不包含索引) select pg_size_pretty(pg_relation_size('表名')); --查出所有表(包含索引)并排序 SELECT table_sch ...

  6. mac使用nvm安装node进行多版本管理

    安装 $ git clone https://github.com/creationix/nvm.git ~/.nvm $ source ~/.nvm/nvm.sh vi ~/.bash_profil ...

  7. Knockout开发中文API系列4–绑定关键字

    目的 Visible绑定通过绑定一个值来确定DOM元素显示或隐藏 示例 <div data-bind="visible: shouldShowMessage"> You ...

  8. 【程序练习】——ini格式转换为xml格式

    ;Configuration of http [http] doamin=www.mysite.com port= cgihome=/cgi-bin   ;Configuration of db [d ...

  9. python里面有人写while 循环用 用while 1 和while True的区别

    由于Python2中,True/False不是关键字,因此我们可以对其进行任意的赋值,这就导致程序在每次循环时都需要对True/False的值进行检查:而对于1,则被程序进行了优化,而后不会再进行检查 ...

  10. Spring Cloud 5分钟搭建教程(附上一个分布式日志系统项目作为参考) - 推荐

    http://blog.csdn.net/lc0817/article/details/53266212/ https://github.com/leoChaoGlut/log-sys 上面是我基于S ...