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. pymongo 使用测试

    >>> import pymongo >>> uri = "mongodb://recall:123456@oceanic.mongohq.com:100 ...

  2. Faiss教程:索引(1)

    索引是faiss的关键知识,我们重点介绍下. 索引方法汇总 有些索引名,我就不翻译了,根据英文名去学习更准确. 索引名 类名 index_factory 主要参数 字节数/向量 精准检索 备注 精准的 ...

  3. wcf中的Message类

    客户端->服务端—>客户端 客户端代码: using (new OperationContextScope(client.InnerChannel))            {       ...

  4. [转]Oracle存储过程给变量赋值的方法

    原文地址:http://blog.csdn.net/drbing/article/details/51821262 截止到目前我发现有三种方法可以在存储过程中给变量进行赋值:1.直接法     :=  ...

  5. 【WPF】ListBox嵌套与事件冒泡

    问题:两个ListBox嵌套后,当鼠标位于内部ListBox上,鼠标滚轮事件会被内部ListBox接收,导致外层ListBox不能用鼠标滚轮滑动!现在的需求是该事件要能给外部ListBox处理,即嵌套 ...

  6. java中反向转义org.apache.commons.lang3.StringEscapeUtils.unescapeJava

    工具类中包含类反向转义的方法: eorderHistory.setSubPrintTemplates(StringEscapeUtils.unescapeJava(eorderHistory.getS ...

  7. Oracel扩展表空间

    --表空间查看 SELECT tbs, sum(totalM) as total, sum(usedM) as UserdM, sum(remainedM) as remainedM, as User ...

  8. MySQL 5.6 GTID 原理以及使用

    转自:http://hamilton.duapp.com/detail?articleId=47 简介 GTID是MySQL 5.6的新特性,其全称是Global Transaction Identi ...

  9. 【css】绝对定位的元素在 ie6 下不显示

    问题描述: 在 ie6 中如果一个浮动元素与绝对定位元素相邻的话,在某些情况下绝对定位元素将会消失. 产生原因: 只有当绝对定位元素的邻近浮动元素的宽度大于父层宽度减 3 时(即如果父层宽度是 300 ...

  10. Entity Framework应用:使用EF的DataBase First模式实现数据库的增删改查

    在上一篇文章中讲解了如何生成EF的DBFirst模式,接下来讲解如何使用DBFirst模式实现数据库数据的增删改查 一.新增数据 新增一个Student,代码如下: static void Add() ...