【C++】脚手架学习笔记 gflags与 gtest

一:GFlags

概念Google gflags 是一个开源 C++ 库,设计用于处理命令行参数。它的核心目标是让程序能够通过命令行或配置文件接受参数,从而轻松地改变程序的行为,而不需要重新编译代码。

理解 :Gflags 的设计将命令行参数视为全局变量。我们在代码中定义一个 flag,它就像一个普通的全局变量一样被访问和使用。当程序启动时,gflags 库会负责解析命令行输入,并将相应的值赋给这些全局变量。

特点
定义简单 :使用宏(如 DEFINE_int32 )直接在代码中定义 flag,就像定义变量一样,非常直观。
类型安全 :支持多种基本类型(如 bool、int32、double、string 等),确保参数类型匹配。
自动文档 :gflags 库可以自动生成关于所有已定义 flag 的帮助信息(使用 --help 命令行参数),极大地方便了用户。
配置文件支持 :除了命令行,它还支持从配置文件中读取参数,方便统一管理和持久化配置。

强大的集成:与 Google 的其他库(如 glog 日志库)有良好的集成,是 Google 基础设施中不可或缺的一部分。

基础使用

宏格式: DEFINE_(name, default_value, "help_message")

name:名称

default_value:默认值

"help_message":注释或说明

:类型

代码实例:

cpp 复制代码
//main.cpp
#include "gflags/gflags.h"
#include <iostream>

DEFINE_int32(port,8080,"这是端口号");
DEFINE_bool(debug,true,"这是调试模式");
DEFINE_string(message,"hello","这是消息");

int main(int argc,char* argv[])
{
    google::ParseCommandLineFlags(&argc,&argv,true);//==解析并赋值,如果没有,就用默认的==
    std::cout<<"这是端口号:"<<FLAGS_port<<std::endl;
    std::cout<<"这是调试模式:"<<FLAGS_debug<<std::endl;
    std::cout<<"这是消息:"<<FLAGS_message<<std::endl;
    return 0;
}
cpp 复制代码
//makefile
main : main.cc
	g++ main.cc -o main -lgflags

注意:

  1. 在使用或者打印这个port的时候,需要在前面加上FLAGS_

运行:

cpp 复制代码
dev@b7357f2dcfa0:~/workspace/gflags$ make
g++ main.cc -o main -lgflags

dev@b7357f2dcfa0:~/workspace/gflags$ ./main 
这是端口号:8080
这是调试模式:1
这是消息:hello

2.在./main 后面加参数

cpp 复制代码
dev@b7357f2dcfa0:~/workspace/gflags$ ./main --port = 9000

ERROR: illegal value '=' specified for int32 flag 'port'

这里的意思是=两边不能有空格

正确写法:

cpp 复制代码
dev@b7357f2dcfa0:~/workspace/gflags$ ./main --port=9000
这是端口号:9000
这是调试模式:1
这是消息:hello
cpp 复制代码
dev@b7357f2dcfa0:~/workspace/gflags$ ./main --nodebug
这是端口号:8080
这是调试模式:0
这是消息:hello

进阶使用

  1. 使用main.config配置文件
    特点:配置⽂件的使⽤,其实就是为了让程序的运⾏参数配置更加标准化,不需要每次运⾏的时候都⼿动收
    ⼊每个参数的数值,⽽是通过配置⽂件,⼀次编写,永久使⽤。
cpp 复制代码
//main/config

--port=9000
--debug=false
--message="hello world"
cpp 复制代码
#include "gflags/gflags.h"
#include <iostream>

DEFINE_int32(port,8080,"这是端口号");
DEFINE_bool(debug,true,"这是调试模式");
DEFINE_string(message,"hello","这是消息");

int main(int argc,char* argv[])
{
    google::ParseCommandLineFlags(&argc,&argv,true);
    std::cout<<"这是端口号:"<<FLAGS_port<<std::endl;
    std::cout<<"这是调试模式:"<<FLAGS_debug<<std::endl;
    std::cout<<"这是消息:"<<FLAGS_message<<std::endl;
    return 0;
}
cpp 复制代码
dev@b7357f2dcfa0:~/workspace/gflags$ ./main --flagfile=./main.config

这是端口号:9000
这是调试模式:0
这是消息:"hello world"
  1. 在别的文件打印参数
cpp 复制代码
//child.cc
#include "gflags/gflags.h"
#include <iostream>

DECLARE_int32(port);
void print()
{
    std::cout<<"child.cc:"<<FLAGS_port<<std::endl;
}

DECLARE_int32(port);:需要声明,不然无法识别出来

cpp 复制代码
#include "gflags/gflags.h"
#include <iostream>

extern void print();

DEFINE_int32(port,8080,"这是端口号");
DEFINE_bool(debug,true,"这是调试模式");
DEFINE_string(message,"hello","这是消息");

int main(int argc,char* argv[])
{
    google::ParseCommandLineFlags(&argc,&argv,true);
    std::cout<<"这是端口号:"<<FLAGS_port<<std::endl;
    std::cout<<"这是调试模式:"<<FLAGS_debug<<std::endl;
    std::cout<<"这是消息:"<<FLAGS_message<<std::endl;
    print();
    return 0;
}

extern void print();:需要声明print这个函数。

makefile:

cpp 复制代码
main : main.cc
	g++ main.cc child.cc -o main -lgflags

二:GTest

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

GTest 的基本结构:

  1. 测试用例组:TEST 或者 TEST_F
    作用:将相关的测试用例组织在一起。
    TEST(测试名称, 测试样例名称)

TEST:主要⽤来创建⼀个简单测试,它定义了⼀个测试函数,在这个函数中可以使⽤任何C++代
码并且使⽤框架提供的断⾔进⾏检查

TEST_F:主要⽤来进⾏多样测试,适⽤于多个测试场景如果需要相同的数据配置的情况,即相同
的数据测不同的⾏为

  1. 测试用例:
    作用:实际执行一个具体的测试操作

头文件:#include <gtest/gtest.h>

框架初始化接口:testing::InitGoogleTest(&argc, argv);

调用测试样例:RUN_ALL_TESTS();

简单样例:

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

TEST(string_cmp,test1)
{
    std::string s = "hello world";
    ASSERT_EQ(11,s.size());
}

int main(int argc,char* argv[])
{
    //框架初始化接口
    testing::InitGoogleTest(&argc,argv);
    return RUN_ALL_TESTS();
}
cpp 复制代码
simple : simple.cc
	g++ simple.cc -o simple -lgtest  

全局事件

概述:这个是针对整个全局的测试用例的,这里需要提前创建一个类,然后继承testing::Environment 类,然后分别实现成员函数 SetUp 和TearDown ,同时在main函数内进⾏调⽤ testing::AddGlobalTestEnvironment(new MyEnvironment);

理解:其实全局测试就是一次测试所有的用例。

大致调用流程:

代码举例:

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

std::vector<int> v;
class GlobalTest : public testing::Environment
{
    public:
    virtual void SetUp() override
    {
        std::cout<<"测试前,准备数据"<<std::endl;
        v.push_back(6);
        v.push_back(3);
        v.push_back(4);
        v.push_back(1);
        std::cout<<"数据准备完成"<<std::endl;
    }
    virtual void TearDown() override
    {
        std::cout<<"测试完,清理数据"<<std::endl;
        v.clear();
        std::cout<<"清理数据完成"<<std::endl;
    }

};


TEST(vector_test,cmp)
{
    ASSERT_EQ(7, v.size());
}

TEST(vector_test,is_true)
{
    ASSERT_EQ(3, v[1]);
}


int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    testing::AddGlobalTestEnvironment(new GlobalTest);
    return RUN_ALL_TESTS();
}
cpp 复制代码
All : simple global

simple : simple.cc
	g++ simple.cc -o simple -lgtest

global : global.cc
	g++ global.cc -o global -lgtest

代码运行图:

单元测试

概述:针对⼀个个测试套件。测试套件的事件机制我们同样需要去创建⼀个类,继承⾃ testing::Test ,然后分别实现成员函数 SetUp 和TearDown ,测试套件的事件机制不需要像全局事件机制⼀样在 main 注册,⽽是需要将我们平时使⽤的 TEST 宏改为TEST_F 宏。

大致过程:

代码用例:

local...cc

cpp 复制代码
#include <gtest/gtest.h>
#include <iostream>
#include <vector>
std::vector<int> v;
class LocalTest : public testing::Test
{
    public:
    virtual void SetUp() override
    {
        std::cout<<"测试前,准备数据"<<std::endl;
        v.push_back(6);
        v.push_back(3);
        v.push_back(4);
        v.push_back(1);
        std::cout<<"数据准备完成"<<std::endl;
    }
    virtual void TearDown() override
    {
        std::cout<<"测试完,清理数据"<<std::endl;
        v.clear();
        std::cout<<"清理数据完成"<<std::endl;
    }
};


TEST_F(LocalTest,cmp)
{
    ASSERT_EQ(4, v.size());
}

TEST_F(LocalTest,is_true)
{
    ASSERT_EQ(3, v[1]);
}

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

makefile:

cpp 复制代码
All : simple global local

simple : simple.cc
	g++ simple.cc -o simple -lgtest

global : global.cc
	g++ global.cc -o global -lgtest
	  
local : local.cc
	g++ local.cc -o local -lgtest

如果想要在测试的时候保存一部分数据作为基础数据,针对⼀个个测试套件。测试套件的事件机制我们同样需要去创建⼀个类,继承⾃ testing::Test ,实现两个静态函数SetUpTestCaseTearDownTestCase ,测试套件的事件机制不需要像全局事件机制⼀样在 main 注册,⽽是需要将我们平时使⽤的 TEST 宏改为 TEST_F 宏。

大致过程是这样子的:

代码:

cpp 复制代码
#include <gtest/gtest.h>
#include <iostream>
#include <vector>
std::vector<int> v;
class LocalTest : public testing::Test
{
    public:
    static void SetUpTestCase() 
    {
        std::cout << "环境第⼀个TEST之前被调⽤,进⾏总体环境配置\n";
    }
    static void TearDownTestCase() 
    {
        std::cout << "环境最后⼀个TEST之后被调⽤,进⾏总体环境清理\n";
    }

    virtual void SetUp() override
    {
        std::cout<<"测试前,准备数据"<<std::endl;
        v.push_back(6);
        v.push_back(3);
        v.push_back(4);
        v.push_back(1);
        std::cout<<"数据准备完成"<<std::endl;
    }
    virtual void TearDown() override
    {
        std::cout<<"测试完,清理数据"<<std::endl;
        v.clear();
        std::cout<<"清理数据完成"<<std::endl;
    }
};



TEST_F(LocalTest,cmp)
{
    ASSERT_EQ(4, v.size());
}

TEST_F(LocalTest,is_true)
{
    ASSERT_EQ(3, v[1]);
}

int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
相关推荐
路痴楷2 小时前
无法定位程序输入点问题
c++·qt·visual studio
2301_810746312 小时前
CKA冲刺40天笔记 - day20-day21 SSL/TLS详解
运维·笔记·网络协议·kubernetes·ssl
Source.Liu2 小时前
【LibreCAD】 RS_Units 类完整解析
c++·qt·rust
Lovely Ruby2 小时前
前端er Go-Frame 的学习笔记:实现 to-do 功能(三),用 docker 封装成镜像,并且同时启动前后端数据库服务
前端·学习·golang
我是一棵无人问荆的小草3 小时前
编码演变史
开发语言·c++
YJlio3 小时前
SDelete 学习笔记(9.18):安全删除、空闲清理与介质回收实战
笔记·学习·安全
potato_may4 小时前
CC++ 内存管理 —— 程序的“五脏六腑”在哪里?
c语言·开发语言·数据结构·c++·内存·内存管理
饕餮怪程序猿4 小时前
A*算法(C++实现)
开发语言·c++·算法
7445 小时前
数据结构(C语言版)线性表-单链表的拓展及应用
笔记·强化学习