I. 基础工具安装

sudo apt-get install vim
sudo apt-get install gcc g++
sudo apt-get install gdb
sudo apt-get install make cmake
sudo apt-get install lrzsz
sudo apt-get install git

II. gflags

一、gflags介绍与安装

gflagsGoogle 开发的一个开源库,用于 C++ 应用程序中命令行参数的声明、定义和解析。gflags 库提供了一种简单的方式来添加、解析和文档化命令行标志(flags),使得程序可以根据不同的运行时配置进行调整。它具有如下几个特点:

  • 易于使用gflags 提供了一套简单直观的 API 来定义和解析命令行标志,使得开发者可以轻松地为应用程序添加新的参数。
  • 自动帮助和文档gflags 可以自动生成每个标志的帮助信息和文档,这有助于用户理解如何使用程序及其参数。
  • 类型安全gflags 支持多种数据类型的标志,包括布尔值、整数、字符串等,并且提供了类型检查和转换。
  • 多平台支持gflags 可以在多种操作系统上使用,包括 WindowsLinuxmacOS
  • 可扩展性gflags 允许开发者自定义标志的注册和解析逻辑,提供了强大的扩展性。

​ 官方文档: https://gflags.github.io/gflags/

​ 代码仓库:https://github.com/gflags/gflags.git

​ 安装命令:

sudo apt-get install libgflags-dev

​ 验证是否安装的命令:

ls /usr/include/gflags/

whereis libgflags.so

二、gflags使用

1. 头文件

#include <gflags/gflags.h>

2. 定义参数

​ 利用 gflag 提供的宏定义来定义参数。该宏的 3 个参数分别为 命令行参数名参数默认值参数的帮助信息

DEFINE_bool(reuse_addr, true, "是否开始网络地址重用选项");
DEFINE_int32(log_level, 1, "日志等级:1-DEBUG,2-WARN,3-ERROR");
DEFINE_string(log_file, "stdout", "日志输出位置设置,默认为标准输出");

gflags 支持定义多种类型的宏函数:

DEFINE_bool
DEFINE_int32
DEFINE_int64
DEFINE_uint64
DEFINE_double
DEFINE_string

3. 使用定义好的参数

​ 我们可以在程序中 通过 FLAGS_name 像正常变量一样访问标志参数。比如在上面的例子中,我们可以通过 FLAGS_reuse_addrFLAGS_log_level 变量来访问命令行参数。

4. 初始化所有参数

​ 当我们定义好参数后,需要告诉可执行程序去处理解析命令行传入的参数,使得 FLAGS_* 变量能得到正确赋值。我们需要在 main 函数中,调用下面的函数来解决命令行传入的所有参数:

google::ParsecommandLineFlags(&argc, &argv, true);

5. 使用例子

#include <gflags/gflags.h>
#include <iostream>

DEFINE_string(ip, "127.0.0.1", "这是服务器的监听ip地址,格式:127.0.0.1");
DEFINE_int32(port, 8800, "这是服务器的监听端口,格式:8800");
DEFINE_bool(debug_enable, true, "是否启用调试模式,格式:true/false");

int main(int argc, char* argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, true);

    std::cout << FLAGS_ip << std::endl;
    std::cout << FLAGS_port << std::endl;
    std::cout << FLAGS_debug_enable << std::endl;
    return 0;
}

6. 其他注意事项

  • 配置文件 设置参数时:

    1. 不要出现多余的空格

    2. 文件格式为 .conf,内容如下所示:

      // main.conf文件
      -ip="192.168.0.1"
      -port=9090
      -debug_enable=true
      
    3. 使用方法./main --flagfile main.conf

  • 命令行设置参数的格式:

    ./main --ip="123456" --port=8080 --debug_enable=false
    
  • 编译文件时 记得链接动态库

    g++ main.cc -lgflags
    
  • 使用下述命令可以显示帮助信息:

    ./main --help
    

Ⅲ、gtest的介绍与安装

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

​ 主要特性如下所示:

  1. 跨平台支持:支持 LinuxWindowsMacOS 等主流平台。
  2. 易于使用:简单直观的语法,容易上手。
  3. 丰富的断言:支持多种断言(如比较、布尔、字符串等)。
  4. 测试组织:支持分组、参数化测试。
  5. 灵活的报告格式:可生成 XML 测试报告,方便与 CI/CD 集成。
  6. Mock 支持:通过 Google Mock 实现更复杂的单元测试。

​ 安装命令如下所示:

sudo apt-get install libgtest-dev

​ 然后可以用下面指令验证是否安装成功:

ls /usr/include/gtest/
whereis libgtest.a

Ⅳ、gtest使用

1. 头文件 && 链接库

注意在编译的时候要链接库

// 头文件:
include <gtest/gtest.h>
    
// makefile文件:
g++ -std=c++17 -o $@ $^ -lgtest

2. 框架初始化接口

testing::InitGoogleTest(&argc, argv);

3. 调用测试样例

​ 一般我们会在程序最后才调用测试样例,故可以直接在主函数的 return 语句中调用!

...
    
int main()
{
    ...
    return RUN_ALL_TESTS(); // 在程序最后进行测试样例调用
}

4. TEST宏

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

    // 1. 同测试下多个测试样例不能同名!
    // 2. 两个名称都是可以用中文的,只要编译器支持正确的编码处理即可!
    TEST(TestSuiteName, TestName) {
        // 测试代码
        EXPECT_TRUE(true);  // 示例断言
    }
    
  • TEST_F:主要用来进行 多样测试,适用于多个测试场景如果需要相同的数据配置的情况, 即相同的数据测不同的行为。

    • FixtureName:测试夹具类名称,继承自 ::testing::Test
    • SetUpTearDown:分别在每个测试用例运行前和运行后执行。
    // 样例示范
    #include <gtest/gtest.h>
    
    class MathTestFixture : public ::testing::Test {
    protected:
        void SetUp() override {
            // 初始化共享资源
            x = 10;
            y = 20;
        }
        void TearDown() override {
        	// 清理工作
    	}
        int x;
        int y;
    };
    
    TEST_F(MathTestFixture, Addition) {
        EXPECT_EQ(x + y, 30);  // 检查 x + y 是否等于 30
    }
    
    TEST_F(MathTestFixture, Multiplication) {
        EXPECT_EQ(x * y, 200);  // 检查 x * y 是否等于 200
    }
    

5. 断言宏

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

ASSERT_系列:如果当前点检测失败,则退出当前测试函数。

EXPECT_系列:如果当前点检测失败,仍然继续往下执行。

​ 下面是常用的断言:

  1. 基本比较
    • EXPECT_EQ(val1, val2):期望 val1 == val2
    • EXPECT_NE(val1, val2):期望 val1 != val2
    • EXPECT_LT(val1, val2):期望 val1 < val2
    • EXPECT_LE(val1, val2):期望 val1 <= val2
    • EXPECT_GT(val1, val2):期望 val1 > val2
    • EXPECT_GE(val1, val2):期望 val1 >= val2
  2. 布尔表达式
    • EXPECT_TRUE(condition):期望 condition 为 true
    • EXPECT_FALSE(condition):期望 condition 为 false
  3. 字符串
    • EXPECT_STREQ(str1, str2):期望 str1 和 str2 内容相同
    • EXPECT_STRNE(str1, str2):期望 str1 和 str2 内容不同
  4. 浮点数
    • EXPECT_FLOAT_EQ(val1, val2):期望 val1 和 val2 近似相等(单精度)
    • EXPECT_DOUBLE_EQ(val1, val2):期望 val1 和 val2 近似相等(双精度)

6. 举个例子

​ 上面 TEST_F 已经举过例子了,这里就举一下 TEST 宏的例子:

#include <iostream>
#include <string>
#include <gtest/gtest.h>
using namespace std;

int add(int a, int b)
{
    return a + b;
}

TEST(测试名称, 加法用例测试) {
    ASSERT_EQ(add(1, 2), 3);
    ASSERT_LT(add(1, 2), 4);
    ASSERT_LT(add(1, 2), 2);
    ASSERT_NE(add(1, 2), 2);
    cout << "执行到尾部!" << endl;
}

TEST(测试名称, 字符串拼接) {
    std::string a = "Hello, ";
    std::string b = "World!";
    ASSERT_EQ(a + b, "Hello, World!");  // 检查字符串拼接
}

int main(int argc, char* argv[])
{
    // 初始化
    testing::InitGoogleTest(&argc, argv);

    // 运行所有测试样例
    return RUN_ALL_TESTS();
}

​ 再写个 makefile 文件:

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

​ 然后执行可以得到下面的信息:

在这里插入图片描述

​ 可以发现并没有执行输出语句,故没有执行到尾部,换成 EXPECT 宏则可以!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐