gtest框架的安装与使用

1、介绍

GTest 是一个跨平台的 C++单元测试框架,由 google 公司发布。gtest 是为了在不同 平台上为编写 C++单元测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化等等测试所需的宏,以及全局测试,单元测试组件。

2、安装

sudo apt-get install libgtest-dev

3、使用

头文件的包含

#include <gtest/gtest.h>

框架初始化接口

testing::InitGoogleTest(&argc, argv);

调用测试样例

RUN_ALL_TESTS();

TEST宏

//这里不需要双引号,且同测试下多个测试样例不能同名

TEST(测试名称, 测试样例名称)
TEST_F(test_fixture,test_name)

  • TEST:主要用来创建一个简单测试, 它定义了一个测试函数, 在这个函数中可以使用任何 C++代码并且使用框架提供的断言进行检查
  • TEST_F:主要用来进行多样测试,适用于多个测试场景如果需要相同的数据配置的情况, 即相同的数据测不同的行为

断言宏

GTest 中的断言的宏可以分为两类:

  • ASSERT_系列:如果当前点检测失败则退出当前函数
  • EXPECT_系列:如果当前点检测失败则继续往下执行

下面是经常使用的断言介绍

// bool 值检查

ASSERT_TRUE(参数),期待结果是 true

ASSERT_FALSE(参数),期待结果是 false

//数值型数据检查

ASSERT_EQ(参数 1,参数 2),传入的是需要比较的两个数 equal

ASSERT_NE(参数 1,参数 2),not equal,不等于才返回 true

ASSERT_LT(参数 1,参数 2),less than,小于才返回 true

ASSERT_GT(参数 1,参数 2),greater than,大于才返回 true

ASSERT_LE(参数 1,参数 2),less equal,小于等于才返回 true

ASSERT_GE(参数 1,参数 2),greater equal,大于等于才返回 true

样例

main.cc

复制代码
#include <gtest/gtest.h>

int abs(int x)
{
        return x > 0 ? x : -x;
}

TEST(abs_test, test1)
{
        ASSERT_TRUE(abs(1) == 1) << "abs(1)=1";
        ASSERT_TRUE(abs(-1) == 1);
        ASSERT_FALSE(abs(-2) == -2);
        ASSERT_EQ(abs(1),abs(-1));
        ASSERT_NE(abs(-1),0);
        ASSERT_LT(abs(-1),2);
        ASSERT_GT(abs(-1),0);
        ASSERT_LE(abs(-1),2);
        ASSERT_GE(abs(-1),0);
}

int main(int argc, char* argv[])
{
        //单元测试框架的初始化
        testing::InitGoogleTest(&argc, argv);
        //开始所有的单元测试
        return RUN_ALL_TESTS();
}

makefile

复制代码
main: main.cc
        g++ -std=c++17 $^ -o $@ -lgtest

运行结果

事件机制

GTest 中的事件机制是指在测试前和测试后提供给用户自行添加操作的机制,而且该机制也可以让同一测试套件下的测试用例共享数据。GTest 框架中事件的结构层次:

测试程序:一个测试程序只有一个 main 函数,也可以说是一个可执行程序是一个测试程序。该级别的事件机制是在程序的开始和结束执行

  • 测试套件:代表一个测试用例的集合体,该级别的事件机制是在整体的测试案例开始和结束执行
  • 测试用例:该级别的事件机制是在每个测试用例开始和结束都执行

事件机制的最大好处就是能够为我们各个测试用例提前准备好测试环境,并在测试完毕后用于销毁环境,这样有个好处就是如果我们有一端代码需要进行多种不同方法的测试,则可以通过测试机制在每个测试用例进行之前初始化测试环境和数据,并在测试完毕后清理测试造成的影响。

GTest 提供了三种常见的的事件:

全局事件

针对整个测试程序。实现全局的事件机制,需要创建一个自己的类,然后继承testing::Environment 类,然后分别实现成员函数 SetUp 和 TearDown,同时在 main 函数内进行调用testing::AddGlobalTestEnvironment(new MyEnvironment);函数添加全局的事件机制

复制代码
#include <iostream> 
#include <gtest/gtest.h>
//全局事件:针对整个测试程序,提供全局事件机制,能够在测试之前配置测试环境
数据,测试完毕后清理数据
//先定义环境类,通过继承 testing::Environment 的派生类来完成
//重写的虚函数接口 SetUp 会在测试之前被调用; TearDown 会在测试完毕后调
用. 
std::unordered_map<std::string, std::string> dict;
class HashTestEnv : public testing::Environment {
 public:
 	virtual void SetUp() override{
 	std::cout << "测试前:提前准备数据!!\n";
 	dict.insert(std::make_pair("Hello", "你好"));
 	dict.insert(std::make_pair("hello", "你好"));
 	dict.insert(std::make_pair("雷吼", "你好"));
 } 
 virtual void TearDown() override{
 	std::cout << "测试结束后:清理数据!!\n";
 	dict.clear();
 } 
};
TEST(hash_case_test, find_test) {
 	auto it = dict.find("hello");
 	ASSERT_NE(it, dict.end());
} 
TEST(hash_case_test, size_test) {
 	ASSERT_GT(dict.size(), 0);
} 
int main(int argc, char *argv[])
{ 
 	testing::AddGlobalTestEnvironment(new HashTestEnv );
 	testing::InitGoogleTest(&argc, argv);
 	return RUN_ALL_TESTS();
}

TestSuite事件

针对一个个测试套件。测试套件的事件机制我们同样需要去创建一个类,继承自 testing::Test,实现两个静态函数 SetUpTestCase 和 TearDownTestCase,测试套件的事件机制不需要像全局事件机制一样在 main 注册,而是需要将我们平时使用的 TEST 宏改为 TEST_F 宏。

  • SetUpTestCase() 函数是在测试套件第一个测试用例开始前执行

  • TearDownTestCase() 函数是在测试套件最后一个测试用例结束后执行

  • 需要注意 TEST_F 的第一个参数是我们创建的类名,也就是当前测试套件的名称,这样在 TEST_F 宏的测试套件中就可以访问类中的成员了。

    #include <iostream>
    #include <gtest/gtest.h>
    //TestSuite:测试套件/集合进行单元测试,即,将多个相关测试归入一组的方式进
    行测试,为这组测试用例进行环境配置和清理
    //概念: 对一个功能的验证往往需要很多测试用例,测试套件就是针对一组相关测
    试用例进行环境配置的事件机制
    //用法: 先定义环境类,继承于 testing::Test 基类, 重写两个静态函数
    SetUpTestCase/TearDownTestCase 进行环境的配置和清理
    class HashTestEnv1 : public testing::Test {
    public:
    static void SetUpTestCase() {
    std::cout << "环境 1 第一个 TEST 之前调用\n";
    }
    static void TearDownTestCase() {
    std::cout << "环境 1 最后一个 TEST 之后调用\n";
    }
    public:
    std::unordered_map<std::string, std::string> dict;
    };
    // 注意,测试套件使用的不是 TEST 了,而是 TEST_F, 而第一个参数名称就是测试
    套件环境类名称
    // main 函数中不需要再注册环境了,而是在 TEST_F 中可以直接访问类的成员变量
    和成员函数
    TEST_F(HashTestEnv1, insert_test) {
    std::cout << "环境 1,中间 insert 测试\n";
    dict.insert(std::make_pair("Hello", "你好"));
    dict.insert(std::make_pair("hello", "你好"));
    dict.insert(std::make_pair("雷吼", "你好"));
    auto it = dict.find("hello");
    ASSERT_NE(it, dict.end());
    }
    TEST_F(HashTestEnv1, sizeof) {
    std::cout << "环境 1,中间 size 测试\n";
    ASSERT_GT(dict.size(), 0);
    }

    int main(int argc, char *argv[])
    {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
    }

结构

能够看到在上例中,有一个好处,就是将数据与测试结合到同一个测试环境类中了,这样与外界的耦合度更低,代码也更清晰。

但是同样的,我们发现在两个测试用例中第二个测试用例失败了,这是为什么呢?这就涉及到了 TestCase 事件的机制。

TestCase 事件

针对一个个测试用例。测试用例的事件机制的创建和测试套件的基本一样,不同地方在于测试用例实现的两个函数分别是 SetUp 和 TearDown, 这两个函数也不是静态函数

  • SetUp()函数是在一个测试用例的开始前执行
  • TearDown()函数是在一个测试用例的结束后执行

也就是说,在 TestSuite/TestCase 事件中,每个测试用例,虽然它们同用同一个事件环境类,可以访问其中的资源,但是本质上每个测试用例的环境都是独立的,这样我们就不用担心不同的测试用例之间会有数据上的影响了,保证所有的测试用例都使用相同的测试环境进行测试。

复制代码
#include <iostream>
#include <gtest/gtest.h>
//TestCase:测试用例的单元测试,即针对每一个测试用例都使用独立的测试环境数据进行测试
//概念:它是针对测试用例进行环境配置的一种事件机制
//用法:先定义环境类,继承于 testing::Test 基类, 在环境类内重写SetUp/TearDown 接口
class HashTestEnv2 : public testing::Test {
 public:
        static void SetUpTestCase() {
                std::cout << "环境 2 第一个 TEST 之前被调用,进行总体环境配置\n";
        } 
        static void TearDownTestCase() {
                std::cout << "环境 2 最后一个 TEST 之后被调用,进行总体环境清理\n";
        } 
        virtual void SetUp() override{
                std::cout << "环境 2 测试前:提前准备数据!!\n";
                dict.insert(std::make_pair("bye", "再见"));
                dict.insert(std::make_pair("see you", "再见"));
        } 
        virtual void TearDown() override{
                std::cout << "环境 2 测试结束后:清理数据!!\n";
                dict.clear();
        }
 public:
        std::unordered_map<std::string, std::string> dict;
};

TEST_F(HashTestEnv2, insert_test) {
        std::cout << "环境 2,中间测试\n";
        dict.insert(std::make_pair("hello", "你好"));
        ASSERT_EQ(dict.size(), 3);
} 
TEST_F(HashTestEnv2, size_test) {
        std::cout << "环境 2,中间 size 测试\n";
        auto it = dict.find("hello");
        ASSERT_EQ(it, dict.end());
         ASSERT_EQ(dict.size(), 2);
} 
int main(int argc, char *argv[])
{ 
        testing::InitGoogleTest(&argc, argv);
        RUN_ALL_TESTS();
        return 0;
}

运行结果:

相关推荐
深海潜水员7 分钟前
【Unity】背包系统 + 物品管理窗口 (上)
开发语言·vscode·游戏·unity·c#·游戏引擎
德育处主任Pro1 小时前
p5.js 用 beginGeometry () 和 endGeometry () 打造自定义 3D 模型
开发语言·javascript·3d
kyranhan1 小时前
C#程序本地运行正常,通过网络下载报错:FileLoadException:“未能加载文件或程序集“xxx.dll”或它的某一个依赖项。
开发语言·c#·wpf
重生之我是Java开发战士2 小时前
【C语言】结构体详解
c语言·开发语言
Ashlee_code3 小时前
南太平洋金融基建革命:斐济-巴新交易所联盟的技术破局之路 ——从关税动荡到离岸红利,跨境科技如何重塑太平洋资本生态
java·开发语言·科技·金融·重构·web3·php
隐-梵3 小时前
2025年测绘程序设计比赛--基于统计滤波的点云去噪(已获国特)
java·开发语言·windows·c#·.net
没有梦想的咸鱼185-1037-16633 小时前
MATLAB科研数据可视化技术
开发语言·机器学习·matlab·信息可视化·数据分析
叉烧钵钵鸡3 小时前
Java ++i 与 i++ 底层原理
java·开发语言·后端
御水流红叶4 小时前
安卓加固脱壳
android·开发语言·python