一: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
注意:
- 在使用或者打印这个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
进阶使用
- 使用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"
- 在别的文件打印参数
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 的基本结构:
- 测试用例组:TEST 或者 TEST_F
作用:将相关的测试用例组织在一起。
TEST(测试名称, 测试样例名称)
TEST:主要⽤来创建⼀个简单测试,它定义了⼀个测试函数,在这个函数中可以使⽤任何C++代
码并且使⽤框架提供的断⾔进⾏检查
TEST_F:主要⽤来进⾏多样测试,适⽤于多个测试场景如果需要相同的数据配置的情况,即相同
的数据测不同的⾏为
- 测试用例:
作用:实际执行一个具体的测试操作
头文件:#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 ,实现两个静态函数SetUpTestCase 和TearDownTestCase ,测试套件的事件机制不需要像全局事件机制⼀样在 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();
}
