1. 安装使用

1.1 安装

在https://code.google.com/p/googletest/ 下载源码

进入msvc, 注意编译方式, 如果是dll, 选择 gtest-md

编译生成lib文件, 然后引入.文件即可使用

1.2 使用

#include "gtest/gtest.h"
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

当然我们也可以输出到xml

int _tmain(int argc, _TCHAR* argv[])
{
testing::GTEST_FLAG(output) = "xml:";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

2. 断言

断言的宏可以分为两类ASSERT系列和EXPECT系列。

TEST(StringCmpTest, Demo)
{
EXPECT_EQ(3, add(1, 2));
ASSERT_EQ(3, add(1, 2));
}

我们再来看下所支持的宏

  • ASSERT_EQ
  • ASSERT_NE
  • ASSERT_LE
  • ASSERT_LT
  • ASSERT_GE
  • ASSERT_GT

  • EXPECT_EQ
  • EXPECT_NE
  • EXPECT_LE
  • EXPECT_LT
  • EXPECT_GE
  • EXPECT_GT

  • ASSERT_TRUE
  • ASSERT_FALSE

  • ASSERT_STREQ
  • ASSERT_STRNE
  • ASSERT_STRCASEEQ
  • ASSERT_STRCASENE

  • ASSERT_FLOAT_EQ
  • ASSERT_DOUBLE_EQ

直接返回成功还是失败

  • FAIL();
  • ADD_FAILURE();

Predicate Assertions

在使用EXPECT_TRUE或ASSERT_TRUE时,有时希望能够输出更加详细的信息,比如检查一个函数的返回值TRUE还是FALSE时,希望能够输出传入的参数是什么,以便失败后好跟踪。因此提供了如下的断言:

  • ASSERT_PRED1(pred1, val1);
  • ASSERT_PRED2(pred2, val1, val2);

如果对这样的输出不满意的话,还可以自定义输出格式化

  • ASSERT_PRED_FORMAT1(pred_format1, val1);`
  • ASSERT_PRED_FORMAT2(pred_format2, val1, val2);

例子

如果我们有这样一个类Arithmetic

我们只需要新建一个ArithmeticUnit.cpp文件,然后写下如下代码:

#include "stdafx.h"
#include "Arithmetic.h"
#include "gtest/gtest.h" TEST(Arithmetic, add){
Arithmetic arith;
int a(1), b(2);
EXPECT_EQ(3, arith.add(1, 2));
}

3. 深入解析gTest

首先从TEST宏入手, 我们看下宏的定义

//1
define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) //2
#define GTEST_TEST(test_case_name, test_name)\
GTEST_TEST_(test_case_name, test_name, \
::testing::Test, ::testing::internal::GetTestTypeId()) //3
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
public:\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private:\
virtual void TestBody();\
static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
.... 所以
1. 最终展开的宏是继承自testing::Test类
2. 我们最终写的代码是放在TestBody()中的
3. 通过静态变量test_info_,调用MakeAndRegisterTestInfo对测试案例进行注册。

看下MakeAndRegisterTestInfo 是如何实现的

TestInfo* MakeAndRegisterTestInfo(
const char* test_case_name,
const char* name,
const char* type_param,
const char* value_param,
TypeId fixture_class_id,
SetUpTestCaseFunc set_up_tc,
TearDownTestCaseFunc tear_down_tc,
TestFactoryBase* factory) {
TestInfo* const test_info =
new TestInfo(test_case_name, name, type_param, value_param,
fixture_class_id, factory);
GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
return test_info;
}

TestInfo对象主要用于包含如下信息:

  1. 测试案例名称(testcase name)

  2. 测试名称(test name)

  3. 该案例是否需要执行

  4. 执行案例时,用于创建Test对象的函数指针

  5. 测试结果

我们还看到,TestInfo的构造函数中,非常重要的一个参数就是工厂对象

internal::TestFactoryBase* factory

它主要负责在运行测试案例时创建出Test对象

new ::testing::internal::TestFactoryImpl<\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>)

我们再来看下 TestFactoryImpl 是如何实现的

template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
public:
virtual Test* CreateTest() { return new TestClass; }
};

我靠, 这也能算是工厂吗~

不过总之流程是, 我们要创建一个测试对象的时候,先调用factory的CreateTest()方法 创建TestInfo对象, 再通过 GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);对TestInfo对象进行注册

UnitTest 是单例

UnitTestImpl 是实现

void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
Test::TearDownTestCaseFunc tear_down_tc,
TestInfo * test_info) {
// 获取或创建了一个TestCase对象,并将testinfo添加到TestCase对象中。
GetTestCase(test_info->test_case_name(),
test_info->test_case_comment(),
set_up_tc,
tear_down_tc)->AddTestInfo(test_info);
}

这里TestCase对象就出来了

  1. TEST宏中的两个参数,第一个参数testcase_name,就是TestCase对象的名称,第二个参数test_name就是Test对象的名称。而TestInfo包含了一个测试案例的一系列信息。

  2. 一个TestCase对象对应一个或多个TestInfo对象。

总结一下gtest里的几个关键的对象:

  1. UnitTest 单例,总管整个测试,包括测试环境信息,当前执行状态等等
  2. Test 我们自己编写的,或通过TEST,TEST_F等宏展开后的Test对象,管理着测试案例的前后事件,具体的执行代码TestBody。
  3. TestCase 测试案例对象,管理着基于TestCase的前后事件,管理内部多个TestInfo。
  4. TestInfo 管理着测试案例的基本信息,包括Test对象的创建方法。

一个简单的UML图如下

4. 撸一个山寨的

撸了一个山寨的,https://github.com/sld666666/TestUnit

gTest详解的更多相关文章

  1. 【转】gitlab CI流水线配置文件.gitlab-ci.yml详解

    目录 GitLab CI流水线配置文件.gitlab-ci.yml详解 实验环境 GitLab CI介绍 .gitlab-ci.yml 配置参数 参数详解 script image services ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  7. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  8. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. .net获取DataTable里面的值(asp.net遍历获取datatable的值)

    方法一:for (int i =0; i < dtb_xx.Rows.Count; i++ ){response.write dtb_xx.Rows[i]["szxxxx1" ...

  2. 【hihoCoder】1037 : 数字三角形

    题目:http://hihocoder.com/problemset/problem/1037 一个迷宫有n层,第 i 层有 i 个房间 从第i层的第i个房间(i, i)可以走到第i+1层的第i个房间 ...

  3. 【转】 Camera模仿3D效果的小例子(图片无限旋转)

    import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactor ...

  4. 只具备内网的服务器通过yum安装软件

    1.在维护过程中,需要统一安装一些软件,可能有的机器只具有内网,有的机器具备外网,可以直接从yum安装,怎么办呢?答:在具备外网的机器上启用yum缓存,这样安装软件的时候本地也缓存了软件安装包,怎样修 ...

  5. Oracle数据库坏块的恢复

    模拟数据块坏块: 对于发生数据块不一致的数据块,如果当前数据库有备份且处于归档模式,那么就可以利用rman工具数据块恢复功能 对数据块进行恢复,这种方法最简单有效,而且可以在数据文件在线时进行,不会发 ...

  6. ScrollTo:平滑滚动到页面指定位置

    使用方法 1.准备jQuery库和scrollTo.js插件. <script type="text/javascript" src="js/jquery.js&q ...

  7. MongoDB的配置、启动、关闭

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系 ...

  8. hihoCoder 1185 连通性·三(Tarjan缩点+暴力DFS)

    #1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出 ...

  9. insert操作卡死的处理过程

    insert操作卡死的处理过程 先看看insert为什么被卡死 SQL> select sql_id from v$sql where sql_text like 'delete from st ...

  10. java并发编程-基础

    线程带来的风险 安全性:多线程操作执行顺序的不可预测性 -- 永远不发生糟糕的事情: 活跃性:代码无法得到执行,死锁.饥饿问题 -- 某件正确的事情最终会发生: 性能问题:活跃性只意味着某件事最终会发 ...