参考:

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入门指南的更多相关文章

  1. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  2. Vue.js 入门指南之“前传”(含sublime text 3 配置)

    题记:关注Vue.js 很久了,但就是没有动手写过一行代码,今天准备入手,却发现自己比菜鸟还菜,于是四方寻找大牛指点,才终于找到了入门的“入门”,就算是“入门指南”的“前传”吧.此文献给跟我一样“白痴 ...

  3. yii2实战教程之新手入门指南-简单博客管理系统

    作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...

  4. 【翻译】Fluent NHibernate介绍和入门指南

    英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...

  5. ASP.NET MVC 5 入门指南汇总

    经过前一段时间的翻译和编辑,我们陆续发出12篇ASP.NET MVC 5的入门文章.其中大部分翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解 ...

  6. 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍

    我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...

  7. 一起学微软Power BI系列-官方文档-入门指南(2)获取源数据

    我们在文章: 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍中,我们介绍了官方入门文档的第一章.今天继续给大家介绍官方文档中,如何获取数据源的相关内容.虽然是英文,但 ...

  8. 一起学微软Power BI系列-官方文档-入门指南(3)Power BI建模

    我们前2篇文章:一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍 和一起学微软Power BI系列-官方文档-入门指南(2)获取源数据 中,我们介绍了官方入门文档与获取 ...

  9. 一起学微软Power BI系列-官方文档-入门指南(4)Power BI的可视化

    在前面的系列文章中,我们介绍了官方有关获取数据,以及建模的原始文档和基本介绍.今天继续给大家介绍官方文档中,有关可视化的内容.实际上获获取数据和建模更注重业务关系的处理,而可视化则关注对数据的解读.这 ...

随机推荐

  1. 抓包整理外篇fiddler———— 会话栏与过滤器[二]

    前言 简单介绍一下会话栏和过滤器 正文 在抓包的时候这两个可以说是必用吧. 会话栏: 会话栏我这里介绍根据左边部分和右边部分. 左边部分是一些图标,有些人发现有个习惯,不习惯看图标. 其实说白了,我们 ...

  2. 内存分析器 (MAT)

    内存分析器 (MAT) 1. 内存分析器 (MAT) 1.1   MAT介绍 MAT是Memory Analyzer tool的缩写.指分析工具. 1.2   MAT作用 Eclipse Memory ...

  3. vue2,vue指令和选项

    vue特点 mvvm框架 响应式(声明式) 组件化(支持自定义组件) 丰富的指令(Dom功能的抽象) 基于选项(template,data,computed,watch,methods) vue文档集 ...

  4. docker部署练习

    三个部署任务 docker部署nginx docker pull nginx #拉取nginx镜像 docker images #检查拉取的镜像 docker run -d -p 3344:80 -- ...

  5. java关键字的概念与特征和标识符的概念和规则

    什么是关键字 比如说邮箱地址 abc@qq.com  123abc@qq.com 这样的只要没有人占用都是和发布的 那么这样呢 hahah@enen@itcast.cn呢 @是电子邮箱当中有特殊含义的 ...

  6. linux学习系列--初识Linux系统

    ### 认识Linux- Linux是一种类UNIX的系统,Unix是1965年在贝尔实验室开发的一个项目,用来开发操作系统- Linux之父-Linus Torvalds在1991年10月5日,他在 ...

  7. 干货分享:小技巧大用处之Bean管理类工厂多种实现方式

    前言:最近几个月很忙,都没有时间写文章了,今天周末刚好忙完下班相对早点(20:00下班)就在家把之前想总结的知识点写出来,于是就有了这篇文章.虽无很高深的技术,但小技巧有大用处. 有时我们经常需要将实 ...

  8. YII学习总结1

    YII 安装(2.0 advanced) 以下借鉴别人的博文  http://www.jb51.net/article/54055.htm 今天终于搞明白怎么安装Yii2了.对于我这种小白来说真是费尽 ...

  9. 「SDOI2016」征途 题解

    「SDOI2016」征途 先浅浅复制一个方差 显然dp,可以搞一个 \(dp[i][j]\)为前i段路程j天到达的最小方差 开始暴力转移 \(dp[i][j]=min(dp[k][j-1]+?)(j- ...

  10. Spring的Model 和 Map的原理

    Model 和 Map 为什么在Model和Map中放值传入后会出现在request的上面. 9.1.源码解析 准备测试代码 @GetMapping("/goto") public ...