【C++】Google Test(gtest)单元测试

news2024/10/5 14:44:48

文章目录

  • Google Test(gtest)单元测试
    • 使用示例
    • 更多用法
      • 测试夹具

Google Test(gtest)单元测试

单元测试是一种软件测试方法,它旨在将应用程序的各个部分(通常是方法或函数)分离出来并独立测试,以确保每个部分都能够按预期工作。

gtest是Google公司发布的一款开源的C/C++单元测试框架。gtest的TEST 宏用于定义单个测试用例,其基本语法为:

TEST(TestCaseName, TestName) {
  // 测试代码
}

其中 TestCaseName为测试用例的名称,用于将相关的测试分组在一起,以便在测试结果中更容易地识别和归类。TestName为具体测试的名称,一般描述测试的目的。

每个测试用例包含一个或多个检查点,这些检查点使用断言来验证代码的行为。包括以EXPECT_ 为前缀的非致命断言,其在测试失败时程序会继续执行;和以 ASSERT_ 味前缀的致命断言,其在测试失败时程序立即终止。基本的非致命断言包括:

  • 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

对应的致命断言:

  • ASSERT_EQ(val1, val2)
  • ASSERT_NE(val1, val2)
  • ASSERT_LT(val1, val2)
  • ASSERT_LE(val1, val2)
  • ASSERT_GT(val1, val2)
  • ASSERT_GE(val1, val2)

除此之外,还有专门用于字符串比较的断言:

  • EXPECT_STREQ(str1, str2):检查 str1str2 是相同的字符串。
  • EXPECT_STRNE(str1, str2):检查 str1str2 是不同的字符串。
  • EXPECT_STRCASEEQ(str1, str2):检查 str1str2 是相同的字符串,忽略大小写。
  • EXPECT_STRCASENE(str1, str2):检查 str1str2 是不同的字符串,忽略大小写。

用于浮点数比较的断言:

  • EXPECT_FLOAT_EQ(val1, val2):检查 val1val2 具有相同的浮点值。
  • EXPECT_DOUBLE_EQ(val1, val2):检查 val1val2 具有相同的双精度值。
  • EXPECT_NEAR(val1, val2, abs_error):检查 val1val2 之间的差值在 abs_error 范围内。

用于布尔值的断言:

  • EXPECT_TRUE(condition):检查 condition 为真。
  • EXPECT_FALSE(condition):检查 condition 为假。

使用示例

项目结构:

gtest_demo/
├── CMakeLists.txt
├── include/
│   └── math_functions.h
├── src/
│   └── math_functions.cpp
└── tests/
    └── test_math_functions.cpp

CMakeLists.txt

# 指定CMake的最低版本
cmake_minimum_required(VERSION 3.10)

# 定义项目名称
project(gtest_demo)

# 设置C++标准为C++11,并且为强制要求
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 添加当前项目的include目录,以便编译器能找到头文件
include_directories(${PROJECT_SOURCE_DIR}/include)

# 添加源文件,生成一个名为math_functions的静态库
add_library(math_functions src/math_functions.cpp)

# 查找Google Test库,确保系统已安装GTest
find_package(GTest REQUIRED)
# 添加GTest的include目录
include_directories(${GTEST_INCLUDE_DIRS})

# 添加测试源文件,生成一个名为runTests的可执行文件
add_executable(runTests tests/test_math_functions.cpp)

# 链接math_functions, gtest库和pthread库到可执行文件runTests
# gtest框架在实现上使用了多线程(pthread)来管理测试并发执行
target_link_libraries(runTests ${GTEST_LIBRARIES} pthread math_functions)

# 启用测试功能
enable_testing()
# 添加一个名为runTests的测试
add_test(NAME runTests COMMAND runTests)

include/math_functions.h

#ifndef MATH_FUNCTIONS_H // 头文件保护
#define MATH_FUNCTIONS_H

int add(int a, int b);
int subtract(int a, int b);
float add(float a, float b);
double add(double a, double b);

#endif 

src/math_functions.cpp :

#include "math_functions.h"

int add(int a, int b) {
    return a + b + 1; // 故意错误
}

int subtract(int a, int b) {
    return a - b;
}

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

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

tests/test_math_functions.cpp:

#include <gtest/gtest.h>
#include "math_functions.h"

// 测试add函数(整数)
TEST(MathFunctionsTest, AddInt) {
    EXPECT_EQ(add(1, 1), 2);
    EXPECT_EQ(add(-1, -1), -2);
    EXPECT_EQ(add(0, 0),2); 
}

// 测试subtract函数
TEST(MathFunctionsTest, Subtract) {
    EXPECT_EQ(subtract(2, 1), 1);
    EXPECT_EQ(subtract(-1, -1), 0);
    EXPECT_EQ(subtract(0, 0), 0); 
}

// 测试add函数(浮点数)
TEST(MathFunctionsTest, AddFloat) {
    EXPECT_FLOAT_EQ(add(0.1f, 0.2f), 0.3f);
    EXPECT_NEAR(add(0.1f, 0.2f), 0.3f, 1e-6);
}

TEST(MathFunctionsTest, AddDouble) {
    EXPECT_DOUBLE_EQ(add(0.1, 0.2), 0.3);
    EXPECT_NEAR(add(0.1, 0.2), 0.3, 1e-6);
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);// 初始化 Google Test 
    return RUN_ALL_TESTS();  // 运行所有测试用例
}

编译和运行测试

    mkdir build
    cd build
    cmake..
    make
    ./runTest
[==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from MathFunctionsTest
[ RUN      ] MathFunctionsTest.AddInt
/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:6: Failure
      Expected: add(1, 1)
      Which is: 3
To be equal to: 2
/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:7: Failure
      Expected: add(-1, -1)
      Which is: -1
To be equal to: -2
/home/hrn/CppProjects/gtest_demo/tests/test_math_functions.cpp:8: Failure
      Expected: add(0, 0)
      Which is: 1
To be equal to: 0
[  FAILED  ] MathFunctionsTest.AddInt (0 ms)
[ RUN      ] MathFunctionsTest.Subtract
[       OK ] MathFunctionsTest.Subtract (0 ms)
[ RUN      ] MathFunctionsTest.AddFloat
[       OK ] MathFunctionsTest.AddFloat (0 ms)
[ RUN      ] MathFunctionsTest.AddDouble
[       OK ] MathFunctionsTest.AddDouble (0 ms)
[----------] 4 tests from MathFunctionsTest (0 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (0 ms total)
[  PASSED  ] 3 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] MathFunctionsTest.AddInt

 1 FAILED TEST

3个测试通过,1个不通过,add函数有误.

更多用法

测试夹具

测试夹具(Test Fixture)用于提供一个环境,允许开发者在多个测试用例之间共享设置和清理的代码,确保每个测试用例都在相同或可控的初始状态下运行。

在gtest中,测试夹具通常是通过派生自::testing::Test类的子类来实现的,并通过TEST_F()宏定义测试用例。

示例:

#include <gtest/gtest.h>
#include <vector>

// 假设有一个简单的类 MyClass
class MyClass {
public:
    MyClass(int data) : basevalue(data) {}
    void add(int data) { basevalue += data; }
    int getdata() const { return basevalue; }

private:
    int basevalue;
};

// 测试夹具类
class MyTest : public ::testing::Test {
protected:
    MyClass *my;
    std::vector<int> sharedVector;

    // 在每个测试用例执行前设置环境
    void SetUp() override {
        my = new MyClass(100);
        sharedVector = {1, 2, 3, 4, 5};
    }

    // 在每个测试用例执行后清理环境
    void TearDown() override {
        delete my;
    }
};

// 使用 TEST_F() 宏编写测试用例
TEST_F(MyTest, test1) {
    my->add(10);
    EXPECT_EQ(my->getdata(), 110);

    sharedVector.push_back(6);
    EXPECT_EQ(sharedVector.size(), 6);
    EXPECT_EQ(sharedVector.back(), 6);
}

TEST_F(MyTest, test2) {
    my->add(100);
    EXPECT_EQ(my->getdata(), 200);

    sharedVector.pop_back();
    EXPECT_EQ(sharedVector.size(), 4);
    EXPECT_EQ(sharedVector.back(), 4);
}

TEST_F(MyTest, test3) {
    my->add(-50);
    EXPECT_EQ(my->getdata(), 50);

    sharedVector[0] = 10;
    EXPECT_EQ(sharedVector[0], 10);
    EXPECT_EQ(sharedVector.size(), 5);
}

TEST_F(MyTest, test4) {
    my->add(0);
    EXPECT_EQ(my->getdata(), 100);

    sharedVector.clear();
    EXPECT_TRUE(sharedVector.empty());
}

在这个示例中,测试夹具类 MyTest 通过继承 ::testing::Test 类,实现了 SetUp()TearDown() 方法。在 SetUp() 方法中,初始化了一个 MyClass 对象和一个 std::vector<int>。在 TearDown() 方法中,清理了 MyClass 对象。

每个测试用例 (test1test2test3test4) 都使用了相同的测试夹具 MyTest,共享了初始化和清理代码。在每个测试用例中,MyClass 对象和 sharedVector 都被重新初始化,以确保测试用例之间相互独立。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1901275.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DevOps实战:使用GitLab+Jenkins+Kubernetes(k8s)建立CI_CD解决方案

一.系统环境 本文主要基于Kubernetes1.21.9和Linux操作系统CentOS7.4。 服务器版本docker软件版本Kubernetes(k8s)集群版本CPU架构CentOS Linux release 7.4.1708 (Core)Docker version 20.10.12v1.21.9x86_64CI/CD解决方案架构图:CI/CD解决方案架构图描述:程序员写好代码之…

测试几个 ocr 对日语的识别情况

测试几个 ocr 对日语的识别情况 1. EasyOCR2. PaddleOCR3. Deepdoc&#xff08;识别pdf中图片&#xff09;4. Deepdoc&#xff08;识别pdf中文字&#xff09;5. Nvidia neva-22b6. Claude 3.5 sonnet 识别图片中的文字7. Claude 3.5 sonnet 识别 pdf 中表格8. OpenAI gpt-4o 识…

CMS Made Simple v2.2.15 远程命令执行漏洞(CVE-2022-23906)

前言 CVE-2022-23906 是一个远程命令执行&#xff08;RCE&#xff09;漏洞&#xff0c;存在于 CMS Made Simple v2.2.15 中。该漏洞通过上传头像功能进行利用&#xff0c;攻击者可以上传一个经过特殊构造的图片文件来触发漏洞。 漏洞详情 CMS Made Simple v2.2.15 中的头像上…

verilog读写文件注意事项

想要的16进制数是文本格式提供的文件&#xff0c;想将16进制数提取到变量内&#xff0c; 可以使用 f s c a n f ( f d 1 , " 也可以使用 fscanf(fd1,"%h",rd_byte);实现 也可以使用 fscanf(fd1,"也可以使用readmemh(“./FILE/1.txt”,mem);//fe放在mem[0…

alphazero学习

AlphaGoZero是AlphaGo算法的升级版本。不需要像训练AlphaGo那样&#xff0c;不需要用人类棋局这些先验知识训练&#xff0c;用MCTS自我博弈产生实时动态产生训练样本。用MCTS来创建训练集&#xff0c;然后训练nnet建模的策略网络和价值网络。就是用MCTSPlayer产生的数据来训练和…

VRPTW(MATLAB):常春藤算法(IVY)求解带时间窗的车辆路径问题VRPTW,MATLAB代码

详细介绍 VRPTW&#xff08;MATLAB&#xff09;&#xff1a;常春藤算法&#xff08;Ivy algorithm&#xff0c;IVY&#xff09;求解带时间窗的车辆路径问题VRPTW&#xff08;提供MATLAB代码&#xff09;-CSDN博客 ********************************求解结果******************…

web零碎知识2

不知道我的这个axios的包导进去没。 找一下关键词&#xff1a; http请求协议&#xff1a;就是进行交互式的格式 需要定义好 这个式一发一收短连接 而且没有记忆 这个分为三个部分 第一个式请求行&#xff0c;第二个就是请求头 第三个就是请求体 以get方式进行请求的失手请求…

C语言 -- 深入理解指针(一)

C语言 -- 深入理解指针&#xff08;一&#xff09; 1.内存和地址1.1 内存1.2 究竟该如何理解编址 2. 指针变量和地址2.1 取地址操作符&#xff08;&&#xff09;​2.2 指针变量和解引用操作符&#xff08;*&#xff09;​​2.2.1 指针变量2.2.2 如何拆解指针类型2.2.3 解引…

Java语言程序设计基础篇(第10版)编程练习题13.18(使用 Rational 类)

第十三章第十八题(使用 Rational 类) 题目要求&#xff1a; 编写程序&#xff0c;使用 Rational 类计算下面的求和数列: 你将会发现输出是不正确的 &#xff0c;因为整数溢出(太大了)。为了解决这个问题 &#xff0c;参见编程练习題13.15。代码参考&#xff1a; package cha…

羊大师:小暑至,热浪涌,三伏悠长防暑忙

随着夏日的脚步悄然加速&#xff0c;我们迎来了小暑节气。小暑&#xff0c;一个预示着盛夏正式拉开序幕的时节&#xff0c;它携带着滚滚热浪&#xff0c;让大地仿佛置身于火炉之中。而随之而来的三伏天&#xff0c;更是长达40天的酷热考验&#xff0c;让人不禁感叹夏日的漫长与…

文件、文本阅读与重定向、路径与理解指令——linux指令学习(一)

前言&#xff1a;本节内容标题虽然为指令&#xff0c;但是并不只是讲指令&#xff0c; 更多的是和指令相关的一些原理性的东西。 如果友友只想要查一查某个指令的用法&#xff0c; 很抱歉&#xff0c; 本节不是那种带有字典性质的文章。但是如果友友是想要来学习的&#xff0c;…

记录第一次使用air热更新golang项目

下载 go install github.com/cosmtrek/airlatest 下载时提示&#xff1a; module declares its path as: github.com/air-verse/air but was required as: github.com/cosmtrek/air 此时&#xff0c;需要在go.mod中加上这么一句&#xff1a; replace github.com/cosmtrek/air &…

VitePress美化

参考资料&#xff1a; https://blog.csdn.net/weixin_44803753/article/details/130903396 https://blog.csdn.net/qq_30678861/category_12467776.html 站点信息修改 首页部分的修改基本都在.vitepress/config.mts,这个文件内修改。 title 站点名称 description 描述 top…

轻松快速上手Thekey库,实现数据加密无忧

Thekey的概述&#xff1a; Thekey库是一个Python库,旨在简化数据加密、解密、签名和验证的过程。它提供了一套简洁易用的接口,用于处理各种加密任务,适合需要在应用程序中实现安全数据处理的开发人员. 安装Thekey库 pip install thekey使用Thekey库进行基本加密和解密操作的…

一种一维时间序列信号变化/事件/异常检测方法(MATLAB)

随着工业物联网、大数据和人工智能的发展&#xff0c;传统工业正在向数字化和智能化升级&#xff0c;从而创造了大量的时间序列数据。通过分析这些数据&#xff0c;可以提供准确可靠的信息服务和决策依据&#xff0c;促进制造业的转型升级。工业物联网在传统工业向“工业 4.0”…

Java+ Idea+ Vue产科信息管理系统源码 什么是产科信息管理系统的门诊管理?

Java Idea Vue产科信息管理系统源码 什么是产科信息管理系统的门诊管理&#xff1f; 产科信息管理系统 门诊管理是现代医疗服务的重要组成部分&#xff0c;它借助信息技术手段&#xff0c;对产科门诊的各个环节进行优化和重构&#xff0c;以提高医疗服务效率、提升患者体验、加…

Windows安装超好用的截图工具——Snipaste

1、下载 官网&#xff1a;https://zh.snipaste.com/ 2、安装 &#xff08;1&#xff09;解压下载的压缩包 &#xff08;2&#xff09;选中Snipaste.exe文件&#xff0c;右键发送到 -- > 桌面快捷方式 &#xff08;3&#xff09;双击桌面Snipaste图标&#xff0c;桌面右下…

Qt 基础组件速学 事件过滤器

学习目标&#xff1a;理解事件过滤器 前置环境 运行环境:qt creator 4.12 学习内容和效果演示&#xff1a; Qt 提供了事件过滤器的机制,允许我们在事件到达目标对象之前对事件进行拦截和处理。这在以下情况下非常有用: 全局事件处理: 我们可以在应用程序级别安装一个事件过…

从文本到安全图像:自动提示优化防止不当内容生成

T2I生成技术已经得到了广泛关注&#xff0c;并见证了如GLIDE、Imagen、DALL-E 2、Stable Diffusion等大型生成模型的发展。尽管这些模型能够根据文本描述生成高质量的图像&#xff0c;促进了书籍插图、品牌标识设计、游戏场景创作等多种实际应用&#xff0c;但它们也被恶意用户…

html+js+css做的扫雷

做了个扫雷&#x1f4a3; 88大小 源代码在文章最后 界面 先点击蓝色开局按钮 然后就可以再扫雷的棋盘上玩 0代表该位置没有雷 其他数字代表周围雷的数量 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&qu…