Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用
在介绍自定义输出机制之前,我们先了解下AssertResult类型函数。(转载请指明出于breaksoftware的csdn博客)
在函数中使用AssertionResult
AssertionResult只有两种类型:
- AssertionSuccess()
- AssertionFailure()
要么成功,要么失败,我们就可以使用基础断言来判断
::testing::AssertionResult IsEven(int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess() << n << " is even";elsereturn ::testing::AssertionFailure() << n << " is odd";
}TEST(TestAssertResult, Check) {EXPECT_FALSE(IsEven(0));EXPECT_TRUE(IsEven(1));
}
我们在IsEven函数中输出了额外的内容(Actual中),便于我们之后查看结果
Value of: IsEven(0)Actual: true (0 is even)
Expected: false
error: Value of: IsEven(1)Actual: false (1 is odd)
Expected: true
自定义输出断言
如果默认的输出结果不能满足我们的需要,或者我们的类型不支持字符流输出,我们就需要自定义输出。我们可以使用
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_PRED_FORMAT1(pred_format1, val1); | EXPECT_PRED_FORMAT1(pred_format1, val1); | pred_format1(val1) is successful |
ASSERT_PRED_FORMAT2(pred_format2, val1, val2); | EXPECT_PRED_FORMAT2(pred_format2, val1, val2); | pred_format2(val1, val2) is successful |
... | ... | ... |
这一系列GTest也是有5对函数,最高是ASSERT/EXPECT_PRED_FORMAT5。我们看下使用的例子
::testing::AssertionResult IsEven2(const char* expr, int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess() << expr << " = " << n << " is even";elsereturn ::testing::AssertionFailure() << expr << " = " << n << " is odd";
}TEST(TestAssertResult, Check2) {int a = 0;int b = 1;EXPECT_PRED_FORMAT1(IsEven2, a);EXPECT_PRED_FORMAT1(IsEven2, b);
}
我们发现,用于判断的表达式要求返回类型是AssertionResult。因为源码底层是
#define GTEST_ASSERT_(expression, on_failure) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (const ::testing::AssertionResult gtest_ar = (expression)) \; \else \on_failure(gtest_ar.failure_message())
其次要求用于判断的表达式第一个参数要是一个const char*类型数据,它用于传递参数的名字。于是上面的测试输出是
error: b = 1 is odd
自定义类型输出
一些情况下,我们自定义类型可能是个复杂的符合结构。C++编译器并不知道怎么输出它,这个时候我们就需要告诉GTest如何去输出了。目前有两种方式
定义输出运算符函数
比如待测类是class Bar。我们只要定义一个方法
::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {return os << bar.DebugString(); // whatever needed to print bar to os
}
通过Bar暴露出来的方法将该对象输出。我们看一个例子
#include <vector>
#include <string>
using namespace std;
class Bar {class Data {public:Data() {strData = "17";intData = 11;}public:std::string strData;int intData;};
public :std::string DebugString() const {std::string output = "Bar.Data.strData = ";output += data.strData;output += "\t";output += "Bar.Data.intData = ";char intBuffer[16] = {0};itoa(data.intData, intBuffer, 10);output += string(intBuffer);return output;}Data data;
};::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {return os << bar.DebugString(); // whatever needed to print bar to os
}bool IsCorrectBarIntVector(vector<pair<Bar, int> > bar_ints) {return false;
}TEST(TestSelfDefineOutput, Test1) {vector<pair<Bar, int> > bar_ints;Bar bar;bar_ints.push_back(pair<Bar, int>(bar, 1));EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))<< "bar_ints = " << ::testing::PrintToString(bar_ints);
}
我们将Bar设计为一个较为复杂的结构,然后定义了一个函数DebugString用于输出其包含的变量。我们让断言进入出错状态,查看其输出
Actual: false
Expected: true
bar_ints = { (Bar.Data.strData = 17 Bar.Data.intData = 11, 1) }
可以看出来,GTest将Vector类型的数据格式化输出(使用了PrintToString方法),并使用我们自定义DebugString输出了自定义结构。
这儿有个有趣的地方,PrintToString的实现,比如它是如何判断它是个容器的
template <typename T>
void PrintTo(const T& value, ::std::ostream* os) {DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
}
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,typename C::iterator* /* it */ = NULL,typename C::const_iterator* /* const_it */ = NULL) {return 0;
}typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
编译器遇到这种情况时,会试着用返回IsContainer的方法去匹配方法,但是如何发现class C没有迭代器,则用返回IsNotContaner的函数取匹配。这样就可以区分模板类是否是容器了。
还有个一is_pointer模板方法,用于判断是否是指针。
template <typename T>
struct is_pointer : public false_type {};template <typename T>
struct is_pointer<T*> : public true_type {};
在我们的测试例子中,由于数据是个容器,且不是指针。那么将会匹配到
template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,false_type /* is not a pointer */,const C& container, ::std::ostream* os) {
其实DefaultPrintTo方法还有其他两个,只是本次没有匹配到
template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,true_type /* is a pointer */,T* p, ::std::ostream* os) {
template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,false_type /* is not a pointer */,const T& value, ::std::ostream* os) {
定义PrintTo方法
有些时候,输出运算符可能被其他业务逻辑占用了。GTest就提供了一个针对性的方法,定义PrintTo方法,我们可以这么去做
void PrintTo(const Bar& bar, ::std::ostream* os) {*os << bar.DebugString(); // whatever needed to print bar to os
}
那么它在什么时候被调用的呢?PrintToString最终会调到如下的函数中,
template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,false_type /* is not a pointer */,const C& container, ::std::ostream* os) {
......for (typename C::const_iterator it = container.begin();it != container.end(); ++it, ++count) {
......internal::UniversalPrint(*it, os);}
......
}
template <typename T1, typename T2>
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {*os << '(';// We cannot use UniversalPrint(value.first, os) here, as T1 may be// a reference type. The same for printing value.second.UniversalPrinter<T1>::Print(value.first, os);*os << ", ";UniversalPrinter<T2>::Print(value.second, os);*os << ')';
}
template <typename T>
class UniversalPrinter {public:GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)static void Print(const T& value, ::std::ostream* os) {PrintTo(value, os);}GTEST_DISABLE_MSC_WARNINGS_POP_()
};
其中UniversalPrinter<T1>::Print(value.first, os)会被我们定义的PrintTo匹配到,从而被调用。
相关文章:
五年循环期限已到,我们又要步入“AI寒冬”了吗?
作者 | Sam Shead译者 | Kolen编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100) 【导读】过去的十年对人工智能来说是一个重要的十年,但该领域的研究人员认为该行业即将进入一个新的阶段。 过去几年里,人工智能这项技术的…

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

Android:problem opening wizard the selected wizard could not be started
直接将Eclipse关掉,重新打开后也许就好了。 如还没好,就执行如下步骤: 1.如果还没有添加ADT,则:Help -> Add New Software -> Add 在“Name”中填入ADT。 2.如果已经安装了ADT,就直接将ADT的地址填写…

Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析
有些时候,我们不仅要测试类暴露出来的公有方法,还要测试其受保护的或者私有方法。GTest测试框架提供了一种方法,让我们可以测试类的私有方法。但是这是一种侵入式的,会破坏原来代码的结构,所以我觉得还是谨慎使用。&am…
170个新项目,579个活跃代码仓库,Facebook开源年度回顾
作者 | Dmitry Vinnik译者 | 泓礼编辑 | 夕颜出品 | AI科技大本营(ID:rgznai100) 【导读】过去一年对于Facebook的开源工程师来说是繁忙的一年。在2019年,Facebook发布了170个新的开源项目,活跃代码仓库产品达到了579…

“怀才不遇”与“怀才不孕”怎么办?
今天在飞机上闲来无事,翻阅深航的随机杂志。一直以来,我乘的比较多的是南航和深航的杂志。南航的杂志基本上都是广告,没有一点可读性的内容。相反,不知道是不是深航的规模较小的原因,找不到合适的广告主吧,…

《评人工智能如何走向新阶段》后记(再续15)
由AI科技大本营下载自视觉中国170. 清华大学全球产业研究院和百度大学Alpha学院于2020年1月5日发表(人工智能)产业智能化白皮书讨论AI发展情况,应用TUMC模型,从技术和综合应用场景的角度,考察热点技术和场景的AI产业化…

Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用
在我们设计测试用例时,我们需要考虑很多场景。每个场景都可能要细致地考虑到到各个参数的选择。比如我们希望使用函数IsPrime检测10000以内字的数字,难道我们要写一万行代码么?(转载请指明出于breaksoftware的csdn博客)…

Linux 指令篇:文件系统--fstab
Linux 指令篇:文件系统-----FSTAB指令:FSTAB使用权限 : 超级使用者 使用方式 : 使用编辑器来修改 /etc/fstab (eg. vi /etc/fstab) 说明 : 存放档案系统与目录结构对应资料的档案 fstab 栏位说明: 第一栏(fs_spec): 实际的 device…

跨平台抓包软件,可以替代Fiddler
2019独角兽企业重金招聘Python工程师标准>>> Zed Attack Proxy (ZAP) 是个强大的跨平台的抓包工具,可以用来替代windows下的Fiddler https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project https://github.com/zaproxy/zaproxy/wiki/Download…
集五福,我用Python
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Crossin先生编辑 | Jane来源 | Crossin的编程教室(ID:crossincode)【导读】你的五福集齐了吗?作为一名技术人,我们是不是可以…

Google Test(GTest)使用方法和源码解析——模板类测试技术分析和应用
写C难免会遇到模板问题,如果要针对一个模板类进行测试,似乎之前博文中介绍的方式只能傻乎乎的一个一个特化类型后再进行测试。其实GTest提供了两种测试模板类的方法,本文我们将介绍方法的使用,并分析其实现原理。(转载…

IT人才职场受宠
面对就业压力的日益增大,就业难,工资水平低等问题困扰着所有的大学生。然而,IT业的迅猛发展却造成了数以万计的网络设计、运行、维护的网络工程师需求的空缺,巨大的人才缺口使得IT业“全线告急”,这也促使更多的研究人…

引用头文件#include queue出错
为什么80%的码农都做不了架构师?>>> 在工程头文件中引用头文件 #include <queue> 莫名奇妙出错,其原因很可能是由于头文件引用问题。 include/c/4.7.1/bits/stl_vector.h:1308:40: error: expected unqualified-id before ‘(’ token…

ZOJ1002 Fire Net(非递归版)
以前用递归的回溯搜索思路做过一次,参见ZOJ1002 Fire Net(递归版),今天想着用非递归的方法试试看,呵呵,比我想象中要难啊,主要还是堆栈里究竟放什么,这一点上思路一直没理清。因此用了整整一天的时间&#…
“数学不行,干啥也不行”骨灰级程序员:其实你们都是瞎努力
编程圈一直都流传着一个段子:一流程序员靠数学,二流程序员靠算法,末端程序员靠百度,低端看高端就是黑魔法。懂的人其实都知道,这不是段子,其实就是程序员的真实写照。想一想,我们日常学习、求职…

Google Test(GTest)使用方法和源码解析——死亡测试技术分析和应用
死亡测试是为了判断一段逻辑是否会导致进程退出而设计的。这种场景并不常见,但是GTest依然为我们设计了这个功能。我们先看下其应用实例。(转载请指明出于breaksoftware的csdn博客) 死亡测试技术应用 我们可以使用TEST声明并注册一个简单的测…
java学习笔记11--Annotation
java学习笔记11--Annotation Annotation:在JDK1.5之后增加的一个新特性,这种特性被称为元数据特性,在JDK1.5之后称为注释,即:使用注释的方式加入一些程序的信息。 java.lang.annotation Annotation接口是所有的Annotat…

GoogleLog(GLog)源码分析
GLog是Google开发的一套日志输出框架。由于其具有功能强大、方便使用等特性,它被众多开源项目使用。本文将通过分析其源码,解析Glog实现的过程。 该框架的源码在https://github.com/google/glog上可以获取到。本文将以目前最新的0.3.3版本源码为范例进行…

Ajax Toolkit 控件学习系列(13) ——FilteredTextBoxExtender 控制输入
这个控件的作用是对TextBox所要输入的内容进行过滤控制。按照自己需要过滤,可以自定义,再或者使用定义好的方式。看效果。效果不是很突出,说明下,就是只能输入大写字母和数字。因为加了限制,但是具体有什么高深的应用呢…
Uber最新开源Manifold,助力机器学习开发者的可视化与调试需求
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Lezhi Li译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导语】2019 年 1 月,Uber 推出了 Manifold,一款与模型无…

jQuery对象和DOM对象使用说明
1.jQuery对象和DOM对象第一次学习jQuery,经常分辨不清哪些是jQuery对象,哪些是 DOM对象,因此需要重点了解jQuery对象和DOM对象以及它们之间的关系.DOM对象,即是我们用传统的方法(javascript)获得的对象,jQuery对象即是用jQuery类库…

[WPF疑难]避免窗口最大化时遮盖任务栏
[WPF疑难]避免窗口最大化时遮盖任务栏 周银辉 WPF窗口最大化时有个很不好的现象是:如果窗口的WindowStyle被直接或间接地设置为None后(比如很多情况下你会覆盖默认的窗体样式,即不采用Windows默认的边框和最大化最等按钮,来打造个…

Google Mock(Gmock)简单使用和源码分析——简单使用
初识Gmock是之前分析GTest源码时,它的源码和GTest源码在同一个代码仓库中(https://github.com/google/googletest)。本文我将以目前最新的Gmock1.7版本为范例,分析其实现原理。(转载请指明出于breaksoftware的csdn博客…
浪潮刘军:为什么说计算力是AI时代“免费的午餐”?
出品 | AI科技大本营(ID:rgznai100)产业AI、元脑生态是浪潮集团2019年度的两大关键词。作为一家以计算力为核心生产力的企业,浪潮还一直强调人工智能计算是未来最重要的计算力,而无论产业AI、元脑生态都构筑于计算的基础设施之上。…

Journey源码分析四:url路由
2019独角兽企业重金招聘Python工程师标准>>> 在入口函数main()的default分支中,对路由进行了注册,现在分析下。 ##main()中路由注册相关代码 源码: httpRouter : httptreemux.New() // Blog and pages as http server.InitializeBlog(httpRou…
“天河二号”总工程师杜云飞谈星光超算应用平台设计
整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】12 月 21-22 日,OpenI/O 启智开发者大会在深圳召开。在大会上, 国家超级计算广州中心总工程师、“天河二号”总工程师杜云飞发表了题为《星光超算应用平台》的主题报告&…

Google Mock(Gmock)简单使用和源码分析——源码分析
源码分析 通过《Google Mock(Gmock)简单使用和源码分析——简单使用》中的例子,我们发现被mock的相关方法在mock类中已经被重新实现了,否则它们也不会按照我们的期待的行为执行。我们通过阅读源码,来分析整个过程的实现逻辑。(转载…

远程控制软件VNC教程和对内网机器控制的实现
网络遥控技术是指由一部计算机(主控端)去控制另一部计算机(被控端),而且当主控端在控制端时,就如同用户亲自坐在被控端前操作一样,可以执行被控端的应用程序,及使用被控端的系统资源…

GRUB2相关概念
GNU GRUB,简称“GRUB”,是一个来自GNU项目的启动引导程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,…