当前位置: 首页 > 编程日记 > 正文

Google Test(GTest)使用方法和源码解析——概况

GTest是很多开源工程的测试框架。虽然介绍它的博文非常多,但是我觉得可以深入到源码层来解析它的实现原理以及使用方法。这样我们不仅可以在开源工程中学习到实用知识,还能学习到一些思想和技巧。我觉得有时候思想和技巧是更重要的。(转载请指明出于breaksoftware的csdn博客)

我们即将要分析的是GTest1.7版本。我们可以通过https://github.com/google/googletest.git得到代码。

官方文档见:

  • https://github.com/google/googletest/blob/master/googletest/docs/primer.md
  • https://github.com/google/googletest/blob/master/googletest/docs/advanced.md

我们先大致熟悉一下GTest的特性。GTest和很多开源工程一样,并不只是针对特定的平台,否则其使用范围将大打折扣,所以GTest具有很好的移植特性可复用性,我们以工程中的代码为例

template <class T, typename Result>
Result HandleSehExceptionsInMethodIfSupported(T* object, Result (T::*method)(), const char* location) {
#if GTEST_HAS_SEH__try {return (object->*method)();} __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINTGetExceptionCode())) {std::string* exception_message = FormatSehExceptionMessage(GetExceptionCode(), location);internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,*exception_message);delete exception_message;return static_cast<Result>(0);}
#else(void)location;return (object->*method)();
#endif  // GTEST_HAS_SEH
}

这段代码只是为了执行模板类T对象的method函数指针指向的方法。其核心就是(object->*method)()这句,但是它却使用了20行的代码去实现,就是为了解决平台的兼容问题。从名字我们可以看出它为了兼容SEH机制——结构化异常处理——一种windows系统上提供给用户处理异常的机制。而这种机制在linux系统上没有。这个函数是GTest为移植特性所做工作的一个很好的代表,我们将在之后的源码介绍中经常见到它的身影。

我们编码时,有时候我们不仅考究逻辑的严谨,还非常注意编码的风格和布局的优美。其实代码就像一件作品,一个不负责任的作者可能是毫无章法的涂鸦手法,而有些有着一定境界的程序员可能就会按照自己的“画风”去绘制——他的“画风”可能你并不喜欢,但是那种风格却是独立和鲜明的,甚至是有一定道理的。而且如果一旦“画风”确定,对于临摹者来说只要照着这样的套路去做,而不用自己发挥自己的风格,这对一个库的发展也是非常有益的。 GTest同样有着良好的组织结构,我们以其自带的Sample1为例

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {EXPECT_EQ(1, Factorial(-5));EXPECT_EQ(1, Factorial(-1));EXPECT_GT(Factorial(-10), 0);
}// Tests factorial of 0.
TEST(FactorialTest, Zero) {EXPECT_EQ(1, Factorial(0));
}// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {EXPECT_EQ(1, Factorial(1));EXPECT_EQ(2, Factorial(2));EXPECT_EQ(6, Factorial(3));EXPECT_EQ(40320, Factorial(8));
}

这段代码是一套完整的测试代码。可以观察发现,每个逻辑使用一个TEST宏控制,其内部也是一系列EXPECT_*宏堆砌。先不论其他风格,单从整齐有规律的书写方式上来说,GTest也算是一个便于结构性编码的样板。我们使用者只要照着这样的样板去编写测试用例,是非常方便的,这也将大大降低我们使用GTest库的门槛。

TEST宏是一个很重要的宏,它构成一个测试特例。现在有必要介绍下其构成,TEST宏的第一个参数是“测试用例名”,第二个参数是“测试特例名”。测试用例(Test Case)是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求(引百度百科),测试特例是测试用例下的一组测试。以以上代码为例,三段TEST宏构成的是一个测试用例——测试用例名是FactorialTest(阶乘方法检测,测试Factorial函数),该用例覆盖了三种测试特例——Negative、Zero和Positive——即检测输入参数是负数、0和正数这三种特例情况。

我们再看一组检测素数的测试用例

TEST(IsPrimeTest, Negative) {// This test belongs to the IsPrimeTest test case.EXPECT_FALSE(IsPrime(-1));EXPECT_FALSE(IsPrime(-2));EXPECT_FALSE(IsPrime(INT_MIN));
}// Tests some trivial cases.
TEST(IsPrimeTest, Trivial) {EXPECT_FALSE(IsPrime(0));EXPECT_FALSE(IsPrime(1));EXPECT_TRUE(IsPrime(2));EXPECT_TRUE(IsPrime(3));
}// Tests positive input.
TEST(IsPrimeTest, Positive) {EXPECT_FALSE(IsPrime(4));EXPECT_TRUE(IsPrime(5));EXPECT_FALSE(IsPrime(6));EXPECT_TRUE(IsPrime(23));
}

这组测试用例的名是IsPrimeTest(测试IsPrime函数),三个测试特例是Negative(错误结果场景)、Trivial(有对有错的场景)和Positive(正确结果场景)。

对于测试用例名和测试特例名,不能有下划线(_)。因为GTest源码中需要使用下划线把它们连接成一个独立的类名

// 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

这样也就要求,我们不能有相同的“测试用例名和特例名”的组合——否则类名重合。

测试用例名和测试特例名的分开,使得我们编写的测试代码有着更加清晰的结构——即有相关性也有独立性。相关性是通过相同的测试用例名联系的,而独立性通过不同的测试特例名体现的。我们通过这段测试代码的运行结果查看一下这两个特性

Running main() from gtest_main.cc
[==========] Running 6 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (0 ms total)[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)[----------] Global test environment tear-down
[==========] 6 tests from 2 test cases ran. (14 ms total)
[  PASSED  ] 6 tests.

从输出结果上,我们看到GTest框架将我们相同测试用例名的场景合并在一起,不同测试特例名的场景分开展现。而且我们还发现GTest有自动统计结果自动格式化输出结果自动调度执行等特性。这些特性也将是之后博文分析的重点。

虽然上例中,所有的执行都是正确的,但是如果以上测试中发生一个错误,也不能影响其他测试——不同测试用例不相互影响、相同测试用例不同测试特例不相互影响。我们称之为独立性。除了独立性,也不失灵活性——一个测试测试特例中可以通过不同宏(ASSERT_*类宏会影响之后执行,EXPECT_*类宏不会)控制是否影响之后的执行。

如果我们编写的测试用例组(如上例是两组)中一组发生了错误,我们希望没出错的那组不用执行了,出错的那组再执行一遍。一般情况下,我们可能需要去删除执行正确的那段测试代码,但是这种方式非常不优美——需要编译或者忘记恢复代码。GTest框架可以让我们通过在程序参数控制执行哪个测试用例,比如我们希望只执行Factorial测试,就可以这样调用程序

./sample1_unittest --gtest_filter=Factorial*

我们可以将以上特性称之为选择性测试

最后一个特性便是预处理。我们测试时,往往要构造复杂的数据。如果我们在每个测试特例中都要构造一遍数据,将是非常繁琐和不美观的。GTest提供了一种提前构建数据的方式。我们以如下代码为例

class ListTest : public testing::Test {protected:virtual void SetUp() {_m_list[0] = 11;_m_list[1] = 12;_m_list[2] = 13;}int _m_list[3];
};
TEST_F(ListTest, FirstElement) {EXPECT_EQ(11, _m_list[0]);
}TEST_F(ListTest, SecondElement) {EXPECT_EQ(12, _m_list[1]);
}TEST_F(ListTest, ThirdElement) {EXPECT_EQ(13, _m_list[2]);
}

我们让ListTest类继承于GTest提供的基类testing::Test,并重载SetUp方法。这样我们每次执行ListTest的一个测试特例时,SetUp方法都会执行一次,从而将数据准备完毕。这样我们只要在一个类中构建好数据就行了。这儿需要注意一下TEST_F宏,它的第一参数要求是类名——即ListTest——不像TEST宏的第一个参数我们可以随便命名。

相关文章:

Reddit票选 | 2019年绝对不能错过的机器学习论文

来源 | reddit.com编辑 | 神经星星 神经小兮技术顾问 | 姜汉&#xff08;openbayes.com&#xff09;来源 | HyperAI超神经&#xff08;ID:HyperAI&#xff09;【导读】回顾 2019 年&#xff0c;人工智能领域时有大事发生&#xff0c;吸引着各界人士的关注。这一年&#xff0c;也…

ASP中的常用服务器检测源码

在写ASP网页时常用的检测代码:服务器现在时间: 引用<% now %>服务器CPU型号: 引用<%Request.ServerVariables("HTTP_UA_CPU")%>当前分辨率: 引用<% Request.ServerVariables("HTTP_UA_PIXELS")%>可显示颜色:[qoute]<%Request.ServerV…

选IDC房时,用脚本截取丢失包和rtt的值作比对

由于业务增长&#xff0c;需要选一个IDC房托管接入。网络质量要求比较高。在IDC给出测试机时&#xff0c;利用smokping来测试&#xff0c;是测出去的包。由于我们在各个地区都有接入机。再从这些接入机去测IDC网络质量&#xff0c;比对指标&#xff1a;丢失的包和rtt返回时延。…

Google Test(GTest)使用方法和源码解析——自动调度机制分析

在《Google Test(GTest)使用方法和源码解析——概况 》一文中&#xff0c;我们简单介绍了下GTest的使用和特性。从这篇博文开始&#xff0c;我们将深入代码&#xff0c;研究这些特性的实现。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 测试用例的自动保存…

D3D中简单的截图方法 (转)

【ZT】D3D中简单的截图方法 试了下&#xff0c;果然可以。在渲染完所有东东后&#xff08;Present之前&#xff09; 获得BackBuffer表面 然后用D3DX的函数保存 voidScreenShot (char*filename) { IDirect3DSurface9 *tmp NULL; IDirect3DSurface9 *back NULL; //生成固定…

2019年,自动化机器学习AutoML技术还火吗? | BDTC 2019

整理 | 王银出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 【导读】12 月 5-7 日&#xff0c;由中国计算机学会主办&#xff0c;CCF 大数据专家委员会承办&#xff0c;CSDN、中科天玑协办的中国大数据技术大会&#xff08;BDTC 2019&#xff09;在北京长城饭店隆重…

第一次使用51cto博客

阿梅第一次使用51cto博客&#xff0c;以后将学习中的总结写到这里来。加油。转载于:https://blog.51cto.com/hopit/1690465

Google Test(GTest)使用方法和源码解析——结果统计机制分析

在分析源码之前&#xff0c;我们先看一个例子。以《Google Test(GTest)使用方法和源码解析——概况 》一文中最后一个实例代码为基准&#xff0c;修改最后一个“局部测试”结果为错误。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; class ListTest : publi…

贾扬清感谢信:阿里开源10年,致敬千万开源人

整理 | 夕颜【导读】2019 年 10 月&#xff0c;有人曾根据 www.gharchive.org 的数据整理出一份 2019 年GitHub 开源贡献排行榜&#xff0c;获取 GitHub 2019 年的 PushEvent&#xff0c;通过分析 GitHub 用户提交记录中的邮件地址&#xff0c;分辨其所属组织。从这份榜单上可…

热烈庆祝我国神七发射成功!

热烈庆祝我国神七发射成功&#xff01;

云计算设计模式(十)——守门员模式

云计算设计模式&#xff08;十&#xff09;——守门员模式 通过使用充当客户端和应用程序或服务之间的代理&#xff0c;验证和进行消毒的请求&#xff0c;并将它们之间的请求和数据的专用主机实例保护的应用程序和服务。这可以提供一个额外的安全层&#xff0c;并限制了系统的攻…

“不会Linux,怎么干程序员?”骨灰级工程师:干啥都不行!

说起优秀程序员的必备技能&#xff0c;我想大家都可以说很多&#xff0c;比如&#xff1a;数据结构、算法、数学、编程语言等等。但是&#xff0c;你可能会忽略了每一个程序员都应该掌握的技能&#xff1a;Linux。想一想&#xff0c;我们日常学习、求职、工作场景的中&#xff…

Google Test(GTest)使用方法和源码解析——Listener技术分析和应用

在《Google Test(GTest)使用方法和源码解析——结果统计机制分析》文中&#xff0c;我么分析了GTest如何对测试结果进行统计的。本文我们将解析其结果输出所使用到的Listener机制。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 解析 源码中&#xff0c;我们…

SSH连接不上Linux的解决方法

SSH连接不上Linux的解决方法: 连续弄了几次&#xff0c;今天早上终于把SSH连接虚拟机连接不通的问题解决了。 先简单说下概要&#xff1a; 主机装的是XP系统&#xff0c;虚拟机用的是red hat Linux。 我用的是nat连接方式是虚拟机内也能上网。 主机是用的校园内寝室共享上网。 …

熬夜翻译完的PureFTPd配置文件

[url]http://www.chinaunix.net[/url] 作者:jeffwu 发表于&#xff1a;2006-07-08 10:31:58 干了个通宵&#xff0c;一边玩一边把配置文件翻译完了&#xff0c;翻得不好的地方还请各位多多提点&#xff0c;少许不是很明白的地方就留在那了。 鼓励转贴&#xff0c;分发&#xf…

挑战NLP、量子计算难题,300多支本科生队伍同场角逐,2020 ASC超算竞赛一触即发...

出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;ASC世界大学生超级计算机竞赛&#xff08;ASCStudent Supercomputer Challenge&#xff09;是由中国发起的世界最大规模的大学生超算竞赛&#xff0c;与美国SC、德国ISC并称全球三大超算竞赛&#xff0c;也是目前全球最…

Google Test(GTest)使用方法和源码解析——断言的使用方法和解析

在之前博文的基础上&#xff0c;我们将介绍部分断言的使用&#xff0c;同时穿插一些源码。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 断言&#xff08;Assertions&#xff09; 断言是GTest局部测试中最简单的使用方法&#xff0c;我们之前博文中举得例子…

精品软件 推荐 硬盘物理序列号修改专家

硬盘物理序列号修改专家不是市面上那些简单修改硬盘驱动器的序列号的东西&#xff0c;而是修改硬盘厂商在烧制时刻录在硬盘盒上的&#xff0c;即&#xff08;硬盘物理序列号&#xff09;&#xff0c;大约20位字母数字的组合1、可以解决部分软件封用户电脑&#xff0c;导致这台电…

知识图谱实体链接是什么?一份“由浅入深”的综述

作者 | 尼古拉瓦砾来源 | Paperweekly&#xff08;ID:paperweekly&#xff09;【导读】这个世界充斥着无数的结构化数据&#xff08;wiki&#xff09;和非结构化数据&#xff08;web&#xff09;&#xff0c;然而&#xff0c;如何将两者有效地集成仍然是个非常困难的问题。本文…

Google Test(GTest)使用方法和源码解析——预处理技术分析和应用

预处理 在《Google Test(GTest)使用方法和源码解析——概况》最后一部分&#xff0c;我们介绍了GTest的预处理特性。现在我们就详细介绍该特性的使用和相关源码。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 测试特例级别预处理 Test Fixtures是建立一个固…

出色管理者的时间管理

出色管理者的时间管理不少管理者都有这样的感慨&#xff1a;“忙了一天&#xff0c;也不知道忙了什么&#xff0c;时间还不够用。”其实&#xff0c;只要有效地运用时间&#xff0c;就可以提高工作效率&#xff0c;在相同的时间里做更多的事&#xff0c;而且做得更好&#xff0…

精品软件 推荐 瑞星 杀毒软件 安全软件

一句话评价一下这软件&#xff1a; 功能好&#xff0c;速度一般。功能&#xff1a;设置中心&#xff1a;最后&#xff0c; 下载地址请到官方下载吧。转载于:https://blog.51cto.com/hangtc/1690981

Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用

在介绍自定义输出机制之前&#xff0c;我们先了解下AssertResult类型函数。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 在函数中使用AssertionResult AssertionResult只有两种类型&#xff1a; AssertionSuccess()AssertionFailure()要么成功&#xff0…

五年循环期限已到,我们又要步入“AI寒冬”了吗?

作者 | Sam Shead译者 | Kolen编辑 | 夕颜出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09; 【导读】过去的十年对人工智能来说是一个重要的十年&#xff0c;但该领域的研究人员认为该行业即将进入一个新的阶段。 过去几年里&#xff0c;人工智能这项技术的…

相知用心.相爱用情

人如花 一生匆匆而过 不要等到你凋落的时候才去眷恋天空&#xff0c;眷恋蝴蝶爱情是短暂的&#xff0c;但却是美丽的该追求的就去追求吧不要留给自己遗憾&#xff0c;不要让自己美丽的花朵枯萎 人生就象一列急驰的火车 机遇和缘分会让许多素昧平生的乘客在旅途中相遇、相识、相…

Android:problem opening wizard the selected wizard could not be started

直接将Eclipse关掉&#xff0c;重新打开后也许就好了。 如还没好&#xff0c;就执行如下步骤&#xff1a; 1.如果还没有添加ADT&#xff0c;则&#xff1a;Help -> Add New Software -> Add 在“Name”中填入ADT。 2.如果已经安装了ADT&#xff0c;就直接将ADT的地址填写…

Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析

有些时候&#xff0c;我们不仅要测试类暴露出来的公有方法&#xff0c;还要测试其受保护的或者私有方法。GTest测试框架提供了一种方法&#xff0c;让我们可以测试类的私有方法。但是这是一种侵入式的&#xff0c;会破坏原来代码的结构&#xff0c;所以我觉得还是谨慎使用。&am…

170个新项目,579个活跃代码仓库,Facebook开源年度回顾

作者 | Dmitry Vinnik译者 | 泓礼编辑 | 夕颜出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 【导读】过去一年对于Facebook的开源工程师来说是繁忙的一年。在2019年&#xff0c;Facebook发布了170个新的开源项目&#xff0c;活跃代码仓库产品达到了579…

“怀才不遇”与“怀才不孕”怎么办?

今天在飞机上闲来无事&#xff0c;翻阅深航的随机杂志。一直以来&#xff0c;我乘的比较多的是南航和深航的杂志。南航的杂志基本上都是广告&#xff0c;没有一点可读性的内容。相反&#xff0c;不知道是不是深航的规模较小的原因&#xff0c;找不到合适的广告主吧&#xff0c;…

《评人工智能如何走向新阶段》后记(再续15)

由AI科技大本营下载自视觉中国170. 清华大学全球产业研究院和百度大学Alpha学院于2020年1月5日发表&#xff08;人工智能&#xff09;产业智能化白皮书讨论AI发展情况&#xff0c;应用TUMC模型&#xff0c;从技术和综合应用场景的角度&#xff0c;考察热点技术和场景的AI产业化…