【C++】GoogleTest入门指南
参考:
GoogleTest官网
基本概念
要使用GoogleTest,需要包含header gtest/gtest.h
断言Assertions
断言是检查条件是否为真的语句,其结果可能是成功或失败,失败分为非致命失败和致命失败两种,后者会终止当前运行,前者则会继续运行。
GoogleTest中,断言类似于函数调用的宏,断言失败时,GoogleTest会输出断言的源文件和行号位置以及失败消息(所有断言都可以使用<<输出自定义失败消息)
ASSERT_*
会抛出致命失败故障的断言,断言失败时中止当前测试函数的运行(不是中断整个TEST)。
ASSERT_EQ(x.size(),y.size()) << "x与y的大小不相同"
EXPECT_*
会抛出非致命失败故障的断言,不会停止当前函数运行,而是继续往下运行下去
EXPECT_EQ(x,y) << "x与y不相等"
断言分类
前缀都会是ASSERT_或者EXPECT_,它们的区别上面已经进行了说明,所以以下都用X_来略写
基本断言
- X_TRUE(condition):断言condition为True
- X_FALSE(condition):断言condition为False
普通比较型断言
- X_EQ(v1,v2):==
- X_NE(v1,v2):!=
- X_LT(v1,v2):<
- X_LE(v1,v2):<=
- X_GT(v1,v2):>
- X_GE(v1,v2):>=
C字符串比较型断言
- X_STREQ(s1,s2):s1==s2
- X_STRNE(s1,s2):s1!=s2
- X_STRCASEEQ(s1,s2):忽略大小写,s1==s2
- X_STRCASENE(s1,s2):忽略大小写,s1!=s2
注意: - Null指针和空字符""是不相同的
- 假如char *s1 = "abc",char *s2 = "abc",那么X_EQ(s1,s2)不通过,因为s1与s2实际上是地址指针,不相同;X_STREQ(s1,s2)通过,因为字符串相同
浮点数比较型断言
对于浮点数,断言只是判断几乎相等
- X_FLOAT_EQ(f1,f2):f1和f2两个float值几乎相等
- X_DOUBLE_EQ(f1,f2):f1和f2两个double值几乎相等
- X_NEAR(v1,v2,abs_error):v1和v2两个浮点数的值差的绝对值不超过abs_error
明确的成功与失败
- SUCCEED():生成一个成功,放行,但是并不代表整个测试成功
- FAIL():生成致命错误,立即终止当前测试
- ADD_FAILURE():生成非致命错误,继续运行测试
- ADD_FAILURE_AT("file_path",line_number):生成非致命错误,输出文件名和行号
- GTEST_SKIP():直接结束当前测试
明确的成功与失败相较于前面的断言更适合判断条件复杂的情况,因为判断条件复杂不适合写成一个表达式condition用于判断。例如if...else if...else if... else...
异常断言
用于验证一段代码是否抛出给定类型的异常
- X_THROW(statement,exception_type):statement代码会抛出exception_type的异常
- X_ANY_THROW(statement):statement代码会抛出异常,不限异常类型
- X_NO_THROW(statement):statement代码不会抛出任何类型异常
自定义布尔函数断言(谓词断言)
- X_PREDn(fun,v1,v2...):拥有n个参数的函数fun会返回True
例如有一个函数equal(a,b),那么就是ASSERT_PRED2(equal,a,b)
与ASSERT_EQ、ASSERT_TRUE()这些断言的区别在于输出的错误信息不同,同时它的功能更加强大
谓词格式化程序断言
普通的断言输出信息的内容是预定好的,如果想要自定义输出的内容,可以使用谓词格式化程序断言
具体接口使用可参考:EXPECT_PRED_FORMAT
为了避免新的断言宏爆炸式增长,GoogleTest提供了很多谓词格式函数,它们可以使用谓词断言的方式组装成需要的断言,例如浮点数的小于等于
using ::testing::FloatLE;
using ::testing::DoubleLE;
...
EXPECT_PRED_FORMAT2(FloatLE, val1, val2);
EXPECT_PRED_FORMAT2(DoubleLE, val1, val2);
匹配器断言
X_THAT(value, matcher):value的值满足matcher的要求
#include "gmock/gmock.h"
using ::testing::AllOf;
using ::testing::Gt;
using ::testing::Lt;
using ::testing::MatchesRegex;
using ::testing::StartsWith;...
EXPECT_THAT(value1, StartsWith("Hello"));
EXPECT_THAT(value2, MatchesRegex("Line \d+"));
ASSERT_THAT(value3, AllOf(Gt(5), Lt(10)));
关于matcher的具体接口文档,详见matchers
类型断言
调用函数::testing::StaticAssertTypeEq<T1,T2>();
用于断言T1和T2是同一种类型,如果断言满足,该函数什么也不做,如果不同,函数调用会无法编译并报错T1 and T2 are not the same type
注意:如果是在类模板或者函数模板中使用时,仅当该函数被实例化(被调用)时才会生效报错,否则不会报错
断言使用的位置
除了在测试代码中使用断言外,在任何C++函数中也都可以使用断言。但是注意,产生致命错误的断言只能用在返回void的函数(构造与析构函数不是返回void的函数)
测试
简单测试
使用
TEST()宏定义和命名测试函数,这个函数是不返回值的普通C++函数函数中可以包含任何有效的C++语句以及各种GoogleTest断言来检查值
测试的结果由断言决定,如果测试时没有任何断言失败(致命或非致命)或者测试程序崩溃,则测试成功
第一个参数是测试套件的名称,第二个参数是测试套件中的测试名称,这两个名称都必须是有效的C++标识符,并且不能含有任何下划线。测试的全名由测试套件和测试名称组成,不同测试套件的测试可以有相同的测试名称
TEST(TestSuiteName, TestName){
... test body ...
}
举个栗子
函数funA有一个输入n,返回n^2,两个测试都属于FunATests测试套件,名字分别是HandlesZeroInput和HandlesPositiveInput用于测试不同的情况
int funA(int n);
TEST(FunATests, HandlesZeroInput){
EXPECT_EQ(funA(0), 0);
}
TEST(FunATests, HandlesPositiveInput){
EXPECT_EQ(funA(1), 1);
EXPECT_EQ(funA(2), 4);
...
}
测试夹具
如果发现自己编写了两个或多个对相似数据进行操作的测试,可以使用测试夹具,它允许我们为多个不同的测试重用相同的对象配置
创建并使用夹具
- 从::tesing::Test派生一个类,它的主体内容设置为protected,因为我们要从子类中访问夹具成员
- 在类中,声明计划使用的所有对象数据
- 如有必要,编写一个默认构造函数或者SetUp()函数来为每个测试准备对象
- 如有必要,编写一个析构函数或者TearDown()函数来释放测试对象数据
- 如有需要,编写函数供使用该测试夹具的测试内使用
- 注意,GoogleTest不会在多个测试中重用同一个测试夹具对象。对于每个TEST_F,GoogleTest会创建一个新的测试夹具对象并立刻调用SetUp(),运行测试主题结束后调用TearDown(),最后删除测试夹具对象
- 使用测试夹具的时候,用TEST_F代替TEST,TEST_F的第一个参数不再是测试套件名,而是测试夹具类名,具体见下方样例
举个栗子
假设我们有一个类Queue需要进行测试,它长这样:
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
定义它的测试夹具类,一般情况下测试夹具类名=类名+Test
class QueueTest : public ::testing::Test {
protected:
void SetUp() override {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// void TearDown() override {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
在这里,TearDown()并不需要,因为我们并不需要进行任何清理工作,直接析构就可以了
使用测试夹具进行测试
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(q0_.size(), 0);
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(n, nullptr);
n = q1_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 1);
EXPECT_EQ(q1_.size(), 0);
delete n;
n = q2_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 2);
EXPECT_EQ(q2_.size(), 1);
delete n;
}
在这个栗子里,第一个TEST_F创建一个QueueTest对象t1,t1.SetUp()后进入测试内容进行使用。测试结束后t1.TearDown()然后销毁。对于第二个TEST_F进行相同的过程
调用测试
TEST()和TEST_F都会自动的隐式注册到GoogleTest,所以并不需要为了测试再重新列举所有定义的测试
在定义测试之后,可以直接使用RUN_ALL_TESTS()来运行所有测试,如果所有测试都通过了,它会返回0。注意,RUNN_ALL_TESTS()会运行所有测试,哪怕这些测试来源于不同的测试套件、不同的源文件。
运行测试的过程
- 保存所有googletest标志的状态
- 为第一个测试创建测试夹具对象,通过SetUp()初始化
- 使用测试夹具对象运行测试
- 测试结束,调用TearDown()清理夹具然后销毁夹具对象
- 恢复所有googletest标志的状态
- 对下一个测试重复以上步骤,直到所有测试都运行结束
注意:不能忽略RUN_ALL_TESTS()的返回值,否则会产生编译器错误。自动化测试服务根据退出代码来判断测试是否通过,而不是通过stdout/sederr来判断,所以main()函数必须返回RUN_ALL_TESTS();
main()的编写
大部分情况下,我们并不需要自己编写main方法,而是直接链接gtest_main(注意不是gtest),这个链接库定义了合适的接入点会帮我们进行测试
如果想自行书写main方法,它需要返回RUN_ALL_TESTS()的返回值
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
在这段代码里,InitGoogleTest()的作用是解析命令行里GoogleTest的指令参数,这允许用户控制测试程序的行为。它必须在RUN_ALL_TESTS之前调用,否则命令行参数不会生效
在旧版本里,使用的是ParseGUnitFlags(),但是目前它已经被弃用,需要使用InitGoogleTest()
后续可填坑
gMock
【C++】GoogleTest入门指南的更多相关文章
- Web API 入门指南 - 闲话安全
Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...
- Vue.js 入门指南之“前传”(含sublime text 3 配置)
题记:关注Vue.js 很久了,但就是没有动手写过一行代码,今天准备入手,却发现自己比菜鸟还菜,于是四方寻找大牛指点,才终于找到了入门的“入门”,就算是“入门指南”的“前传”吧.此文献给跟我一样“白痴 ...
- yii2实战教程之新手入门指南-简单博客管理系统
作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...
- 【翻译】Fluent NHibernate介绍和入门指南
英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...
- ASP.NET MVC 5 入门指南汇总
经过前一段时间的翻译和编辑,我们陆续发出12篇ASP.NET MVC 5的入门文章.其中大部分翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解 ...
- 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍
我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...
- 一起学微软Power BI系列-官方文档-入门指南(2)获取源数据
我们在文章: 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍中,我们介绍了官方入门文档的第一章.今天继续给大家介绍官方文档中,如何获取数据源的相关内容.虽然是英文,但 ...
- 一起学微软Power BI系列-官方文档-入门指南(3)Power BI建模
我们前2篇文章:一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍 和一起学微软Power BI系列-官方文档-入门指南(2)获取源数据 中,我们介绍了官方入门文档与获取 ...
- 一起学微软Power BI系列-官方文档-入门指南(4)Power BI的可视化
在前面的系列文章中,我们介绍了官方有关获取数据,以及建模的原始文档和基本介绍.今天继续给大家介绍官方文档中,有关可视化的内容.实际上获获取数据和建模更注重业务关系的处理,而可视化则关注对数据的解读.这 ...
随机推荐
- 临近梯度下降算法(Proximal Gradient Method)的推导以及优势
邻近梯度下降法 对于无约束凸优化问题,当目标函数可微时,可以采用梯度下降法求解:当目标函数不可微时,可以采用次梯度下降法求解:当目标函数中同时包含可微项与不可微项时,常采用邻近梯度下降法求解.上述三种 ...
- 前端学做 PPT
前端学做 PPT 公司做技术分享.年终总结都需要用到ppt. 要快速.省事的做出高质量的 ppt,一方面需要熟练使用制作 ppt 的工具,另一方面得知道用工具做成什么样子才是好作品.前者比较简单,后者 ...
- python type 与 metaclass理解
简介 众所周知,type在一般情况下,我们都会去获取一个对象的类型,然后进行类型的比较:除此之外,type还有一个不为人知的作用:动态的创建类.在了解这个之前,首先了解以下type和isinstanc ...
- python主动杀死线程
简介 在一些项目中,为了防止影响主进程都会在执行一些耗时动作时采取多线程的方式,但是在开启线程后往往我们会需要快速的停止某个线程的动作,因此就需要进行强杀线程,下面将介绍两种杀死线程的方式. 直接强杀 ...
- SkiaSharp 之 WPF 自绘 拖曳小球(案例版)
感谢各位大佬和粉丝的厚爱和关心( 催更),我会再接再厉的,其实这也是督促自己的一种方式,非常感谢. 刚写了一篇万字长文,自己也休养生息(低调发育)了一段时间,接下来来几个小案例. 拖曳小球 WPF的拖 ...
- 什么是WordPress
首先,假设您没有WordPress的经验: 我将从基础开始. 在本教程中,我将回答问题:"什么是WordPress?" 在这篇文章中,我将说明您可以在哪里获得WordPress以及 ...
- RabbitMQ延迟消息:死信队列 | 延迟插件 | 二合一用法+踩坑手记+最佳使用心得
前言 前段时间写过一篇: # RabbitMQ:消息丢失 | 消息重复 | 消息积压的原因+解决方案+网上学不到的使用心得 很多人加了我好友,说很喜欢这篇文章,也问了我一些问题. 因为最近工作比较忙, ...
- Axure RP 8 实现 圆角文本框 圆角带筛选的下拉列表框 可自动显示滚动条
刚开始用Axure 会发现 Axure 元件库并不是很齐全,很多元件需要自己想办法解决 或者去网上去找.其实个人建议网上有现成的元件可以就下载就不必花时间去折腾.除非你也想练练手,原型这种东西除非高保 ...
- 日夕如是寒暑不间,基于Python3+Tornado6+APScheduler/Celery打造并发异步动态定时任务轮询服务
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_220 定时任务的典型落地场景在各行业中都很普遍,比如支付系统中,支付过程中因为网络或者其他因素导致出现掉单.卡单的情况,账单变成了 ...
- goalng-sync/atomic原子操作
目录 1.go已经提供了锁,为什么还需要atomic原子操作? 2.atomic原子操作为什么比mutex快? 3.CAS 4.互斥锁与原子操作区别 5.原子操作方法 5.1 atomic.AddIn ...