【视频点播系统】GTest 介绍及使用

GTest 介绍及使用

  • [一. gtest 介绍](#一. gtest 介绍)
  • [二. gtest 安装](#二. gtest 安装)
  • [三. gtest 使用](#三. gtest 使用)
    • [1. 头文件和链接库](#1. 头文件和链接库)
    • [2. 框架初始化接口](#2. 框架初始化接口)
    • [3. 调用测试样例](#3. 调用测试样例)
    • [4. TEST 宏](#4. TEST 宏)
    • [5. 断言宏](#5. 断言宏)
  • [四. gtest 使用样例](#四. gtest 使用样例)
    • [1. 目录结构](#1. 目录结构)
      • [4.2 项目构建](#4.2 项目构建)
      • [4.3 样例编写](#4.3 样例编写)
    • [5. gtest 事件机制](#5. gtest 事件机制)
      • [5.1 全局事件](#5.1 全局事件)
      • [5.2 TestCase 事件](#5.2 TestCase 事件)
      • [5.3 TestSuite 事件](#5.3 TestSuite 事件)

一. gtest 介绍

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

二. gtest 安装

bash 复制代码
sudo apt-get install libgtest-dev

在环境搭建中已经内置 gtest,这里不需要再次安装了。

三. gtest 使用

1. 头文件和链接库

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

程序编译时库的链接

bash 复制代码
-lgtest

2. 框架初始化接口

cpp 复制代码
int main(int argc, char *argv[])
{
	testing::InitGoogleTest(&argc, argv);
	return 0;
}

3. 调用测试样例

cpp 复制代码
RUN_ALL_TESTS();

4. TEST 宏

cpp 复制代码
// 这里不需要双引号,且同测试下多个测试样例不能同名
TEST(测试名称, 测试样例名称)

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

5. 断言宏

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

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

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

cpp 复制代码
// 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

四. gtest 使用样例

1. 目录结构

bash 复制代码
gtest/
|-- global.cc
|-- local1.cc
|-- local2.cc
|-- main.cc
|-- makefile

4.2 项目构建

bash 复制代码
# makefile
all: main global local1 local2
main: main.cc
	g++ -o $@ $^ -std=c++17 -lgtest
global: global.cc
	g++ -o $@ $^ -std=c++17 -lgtest
local1: local1.cc
	g++ -o $@ $^ -std=c++17 -lgtest
local2: local2.cc
	g++ -o $@ $^ -std=c++17 -lgtest

.PHONY: clean
clean:
	rm -f main global local1 local2

4.3 样例编写

cpp 复制代码
// main.cc
#include <iostream>
#include <gtest/gtest.h>
#include <unordered_map>

// 1.定义测试用例
TEST(unordered_map, insert) {
    std::unordered_map<int, int> map;
    map.insert(std::make_pair(1, 1));
    map.insert(std::make_pair(2, 2));
    map.insert(std::make_pair(3, 3));
    EXPECT_EQ(map.size(), 3);
}
TEST(unordered_map, find) {
    std::unordered_map<int, int> map;
    map.insert(std::make_pair(1, 1));
    map.insert(std::make_pair(2, 2));
    map.insert(std::make_pair(3, 3));
    EXPECT_EQ(map.find(1)->second, 1);
}

int main(int argc, char* argv[])
{
    // 2.初始化测试环境
    testing::InitGoogleTest(&argc, argv);

    // 3.执行测试用例
    return RUN_ALL_TESTS();
}

5. gtest 事件机制

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

  • 测试程序:一个测试程序只有一个 main 函数,也可以说是一个可执行程序是一个测试程序。该级别的事件机制是在程序的开始和结束执行。
  • 测试套件:代表一个测试用例的集合体,该级别的事件机制是在整体的测试案例开始和结束执行。
  • 测试用例:该级别的事件机制是在每个测试用例开始和结束都执用。

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

gtest 提供了三种常见的的事件。

5.1 全局事件

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

  • SetUp() 函数是在所有测试用例的开始前执行。
  • TearDown() 函数是在所有测试用例的结束后执行。
cpp 复制代码
// global.cc
#include <iostream>
#include <gtest/gtest.h>
#include <unordered_map>

// 全局变量
std::unordered_map<int, int> map;

// 1.定义全局测试环境类
class GlobalTestEnvironment : public testing::Environment {
public:
    virtual void SetUp() {
        std::cout << "执行于所有测试用例之前" << std::endl;
        map.insert(std::make_pair(1, 1));
        map.insert(std::make_pair(2, 2));
        map.insert(std::make_pair(3, 3));
    }
    virtual void TearDown() {
        std::cout << "执行于所有测试用例之后" << std::endl;
        map.clear();
    }
};

// 2.定义测试用例
TEST(GlobalTestEnvironment, remove) {
    EXPECT_EQ(map.size(), 3);
    map.erase(1);
}
TEST(GlobalTestEnvironment, find) {
    EXPECT_EQ(map.find(1), map.end());
}

int main(int argc, char* argv[])
{
    // 3.初始化测试环境
    testing::InitGoogleTest(&argc, argv);

    // 4.注册全局测试环境
    testing::AddGlobalTestEnvironment(new MyEnvironment);

    // 5.执行测试用例
    return RUN_ALL_TESTS();
}

5.2 TestCase 事件

针对一个个测试用例。测试用例的事件机制我们同样需要去创建一个类,继承 testing::Test 类,重写两个虚函数 SetUp 和 TearDown,测试用例的事件机制不需要像全局事件机制一样在 main 注册,而是需要将我们平时使用的 TEST 宏改为 TEST_F 宏。

  • SetUp() 函数是在每个测试用例的开始前执行。
  • TearDown() 函数是在每个测试用例的结束后执行。
  • 需要注意 TEST_F 的第一个参数是我们创建的类名,也就是当前测试套件的名称,这样在 TEST_F 宏的测试套件中就可以访问类中的成员了。
cpp 复制代码
// local1.cc
#include <iostream>
#include <gtest/gtest.h>
#include <unordered_map>

// 1.定义局部测试环境类
class LocalTestSuite : public testing::Test {
public:
    virtual void SetUp() {
        std::cout << "执行于每个测试用例之前" << std::endl;
        map.insert(std::make_pair(1, 1));
        map.insert(std::make_pair(2, 2));
        map.insert(std::make_pair(3, 3));
    }
    virtual void TearDown() {
        std::cout << "执行于每个测试用例之后" << std::endl;
        map.clear();
    }
public:
    std::unordered_map<int, int> map;
};

// 2.定义测试用例
TEST_F(LocalTestSuite, find) {
    EXPECT_EQ(map.size(), 3);
    EXPECT_EQ(map.find(1)->second, 1);
    map.erase(1);
}
TEST_F(LocalTestSuite, erase) {
    map.erase(1);
    EXPECT_EQ(map.size(), 2);
}

int main(int argc, char* argv[])
{
    // 3.初始化测试环境
    testing::InitGoogleTest(&argc, argv);

    // 4.执行测试用例
    return RUN_ALL_TESTS();
}

5.3 TestSuite 事件

针对一个个测试套件。测试套件的事件机制的创建和测试套件的基本一样,不同地方在于实现两个静态函数 SetUpTestSuite 和 TearDownTestSuite (这里是隐藏)。

  • SetUpTestSuite() 函数是在测试套件第一个测试用例开始前执行。
  • TearDownTestSuite() 函数是在测试套件最后一个测试用例结束后执行。

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

cpp 复制代码
// local2.cc
#include <iostream>
#include <memory>
#include <gtest/gtest.h>
#include <unordered_map>

// 1.定义局部测试环境类
class LocalTestSuite : public testing::Test {
public:
    // TestSuite 事件
    static void SetUpTestSuite() {
        std::cout << "执行于所有测试用例之前" << std::endl;
        shared_map = new std::unordered_map<int, int>;
        shared_map->insert(std::make_pair(1, 1));
        shared_map->insert(std::make_pair(2, 2));
        shared_map->insert(std::make_pair(3, 3));
    }
    static void TearDownTestSuite() {
        std::cout << "执行于所有测试用例之后" << std::endl;
        delete shared_map;
        shared_map = nullptr;
    }
    // TestCase 事件
    virtual void SetUp() {
        std::cout << "执行于每个测试用例之前" << std::endl;
        // 拷贝共享数据,保证测试隔离
        local_map = *shared_map;
    }
    virtual void TearDown() {
        std::cout << "执行于每个测试用例之后" << std::endl;
        local_map.clear();
    }
public:
    // 套件级共享资源
    static std::unordered_map<int, int>* shared_map;
    // 用例级私有数据
    std::unordered_map<int, int> local_map;
};

// 静态成员定义
std::unordered_map<int, int>* LocalTestSuite::shared_map = nullptr;

// 2.定义测试用例
TEST_F(LocalTestSuite, find) {
    EXPECT_EQ(local_map.size(), 3);
    EXPECT_EQ(local_map.find(1)->second, 1);
    local_map.erase(1);
}
TEST_F(LocalTestSuite, erase) {
    local_map.erase(1);
    EXPECT_EQ(local_map.size(), 2);
}

int main(int argc, char* argv[])
{
    // 3.初始化测试环境
    testing::InitGoogleTest(&argc, argv);

    // 4.执行测试用例
    return RUN_ALL_TESTS();
}
相关推荐
emma羊羊2 天前
【log4j】
log4j
小马哥编程2 天前
单元测试中,开发模拟器(Simulator)、测试驱动器(Test driver)、桩(Stub),
单元测试·log4j
你这个代码我看不懂3 天前
SpringBoot单元测试Mock和Spy
spring boot·单元测试·log4j
tqs_123454 天前
Spring 框架中的 IoC (控制反转) 和 AOP (面向切面编程) 及其应用
java·开发语言·log4j
sunnyday04266 天前
Spring Boot 日志配置详解:log4j2.xml 的完整配置指南
xml·spring boot·log4j
小涛不学习8 天前
深入浅出Spring核心:IOC与AOP的本质与实现原理
log4j
w***765513 天前
SpringBoot Test详解
spring boot·后端·log4j
Knight_AL14 天前
Maven 生命周期详解(validate → deploy)
java·log4j·maven
岁岁种桃花儿14 天前
Spring Boot核心插件全解析(官方+第三方,附使用场景)
log4j·springboot·插件