使用vscode在CMake工程中集成gtest共享库进行单元测试

news2024/9/28 23:33:15

使用vscode在CMake工程中集成gtest共享库做单元测试

  • 一、概述
  • 二、工程内容清单
  • 三、CMakeLists.txt内容说明
  • 四、构建工程

一、概述

本文主要介绍如何在一个多层次目录结构的CMAKE工程中以共享库的形式集成gtest进行单元测试。

关于如何使用CMake管理多层次目录结构的CMake工程,可以参考我的这一篇博文:
《多层次目录结构的CMake工程管理》
本文的工程基本就采用上述博文中的样例,只不过稍微改造了一下C++的代码。

关于如何在CMake中使用外部共享库和头文件,请参考我的这一篇博文:
《CMake使用外部动态库/静态库和头文件》

关于如何使用CMake构建和安装gtest,请参考我的这一篇博文:
《在linux上使用CMake构建和安装gtest》

本文代码结构为:

[hubing@192 gtestdemo]$ tree
.
├── CMakeLists.txt
├── doc
│   └── README.md
└── src
    ├── CMakeLists.txt
    ├── main.cpp
    └── utils
        ├── CMakeLists.txt
        ├── MathUtils.cpp
        ├── MathUtils.hpp
        └── ut
            ├── CMakeLists.txt
            └── testMathUtils.cpp

4 directories, 9 files

20230104182047

二、工程内容清单

在src/utils目录下,有一个ut子目录,用于放置ut文件,每个ut文件,用于测试src/utils下对应的文件。比如testMathUtils.cpp就专门用来测试MathUtils.cpp/hpp。这里仅以一个文件作为示例,如果有多个文件,则以此类推。本文重点关注的就是如何使用CMake来集成gtest并跑通这个ut test。

这里把所有文件的内容都贴出来,方便参考。

顶层目录名为gtestdemo,后续的路径以此为根目录。

gtestdemo/src/main.cpp

#include <iostream>
#include "MathUtils.hpp"

int main(int, char**) {
    std::cout << "Hello, gtestdemo!"<< std::endl;

    auto mathUtils = utils::math::MathUtils();
    std::cout << "4! = " << mathUtils.getFactorial(4) << std::endl;
    std::cout << "check whether 10 is a prime number: " << mathUtils.isPrime(10) << std::endl;
    std::cout << "check whether 11 is a prime number: " << mathUtils.isPrime(11) << std::endl;
}

gtestdemo/src/utils/MathUtils.hpp

namespace utils::math
{

class MathUtils
{
public:

    // Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
    int getFactorial(int n);

    // Returns true if n is a prime number.
    bool isPrime(int n);
};

}

gtestdemo/src/utils/MathUtils.cpp

#include "MathUtils.hpp"

namespace utils::math
{

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int MathUtils::getFactorial(int n) {
    int result = 1;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }
 
    return result;
}

bool MathUtils::isPrime(int n) {
    // Trivial case 1: small numbers
    if (n <= 1) return false;
 
    // Trivial case 2: even numbers
    if (n % 2 == 0) return n == 2;
 
    // Now, we have that n is odd and n >= 3.
    // Try to divide n by every odd number i, starting from 3
    for (int i = 3; ; i += 2) {
        // We only have to try i up to the squre root of n
        if (i > n / i) break;
 
        // Now, we have i <= n/i < n.
        // If n is divisible by i, n is not prime.
        if (n % i == 0) return false;
    }
    // n has no integer factor in the range (1, n), and thus is prime.
    return true;
}

}

gtestdemo/src/utils/ut/testMathUtils.cpp

#include <gtest/gtest.h>
#include "../MathUtils.cpp"


class TestMathUtils : public testing::Test
{
protected:
    void SetUp() override
    {
        // 空,仅做示范
    }
    void TearDown() override
    {
        // 空,仅做示范
    }

    utils::math::MathUtils mathUtils{};
};

TEST_F(TestMathUtils, testFactorial)
{
    EXPECT_EQ(1, mathUtils.getFactorial(0));
    EXPECT_EQ(1, mathUtils.getFactorial(1));
    EXPECT_EQ(24, mathUtils.getFactorial(4));
}

TEST_F(TestMathUtils, testIsPrime)
{
    EXPECT_FALSE(mathUtils.isPrime(1));
    EXPECT_TRUE(mathUtils.isPrime(2));
    EXPECT_TRUE(mathUtils.isPrime(3));
    EXPECT_FALSE(mathUtils.isPrime(4));
    //实际是EXPECT_TRUE(mathUtils.isPrime(5)); 
    //这里做个错误示范,方便观察输出
    EXPECT_FALSE(mathUtils.isPrime(5));
}

gtestdemo/CMakeLists.txt:

cmake_minimum_required(VERSION 3.0.0)
project(gtestdemo VERSION 0.1.0)

# enable c++ 11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# take respectives flags for debug & release process 
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-std=c++11 -g -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-std=c++11 -g -O2")

# default build type : Debug
if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug)
endif()

# 在add_subdirectory之前调用enable_testing
include(CTest)
enable_testing()

add_subdirectory(src bin)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

gtestdemo/src/CMakeLists.txt:

add_subdirectory(utils)

add_executable(gtestdemo main.cpp)

target_link_libraries(gtestdemo PUBLIC utils)

message(STATUS "this is BINARY dir " ${PROJECT_BINARY_DIR})
message(STATUS "this is SOURCE dir " ${PROJECT_SOURCE_DIR})
target_include_directories(gtestdemo PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/src/utils")

gtestdemo/src/utils/CMakeLists.txt:

add_library(utils MathUtils.cpp)

add_subdirectory(ut)

gtestdemo/src/utils/ut/CMakeLists.txt:

include_directories(/usr/local/include/gtest/)
link_directories(/usr/local/lib64)

add_executable(testMathUtils testMathUtils.cpp)
add_test(NAME testMathUtils COMMAND testMathUtils)

target_link_libraries(testMathUtils gtest gtest_main)

三、CMakeLists.txt内容说明

源代码层面的相关内容就不再复述了,相关内容都可以从《多层次目录结构的CMake工程管理》中找到说明。这里主要涉及ut相关的内容。

首先在最顶级的CMakeLists.txt中,必须通过enable_testing()来使能单元测试。且最好把它放在add_subdirectory语句之前。 核心部分为:

enable_testing()
add_subdirectory(src bin)

然后,再在src/utils/CMakeLists.txt中,使用add_subdirectory指令把下面的ut子目录添加进工程得以编译,核心语句为:

add_subdirectory(ut)

最后就是src/utils/ut/CMakeLists.txt了。本例中gtest由于是采用默认安装路径的,所以它被安装到了/usr/local目录下,这并不是标准的搜索路径。因为要以共享库的形式加载gtest,所以我们必须通过相关指令来指明gtest的共享库位于何处,以及相关头文件位于何处。

# 指明头文件路径
include_directories(/usr/local/include/gtest/)
# 指明共享库路径
link_directories(/usr/local/lib64)

然后使用add_executable添加可执行程序,再使用add_test指令将其添加到CMake中,使CMake能够发现相关测试。如果不使用add_test将测试到CMake,那么待所有内容编译完成后,CMake将检测不到我们的单元测试,会提示:[ctest] No tests were found!!!

当然了,我们可以手工执行二进制可执行文件testMathUtils,但这终究不是很方便。当ut文件数目变得庞大时,更加不可能手工去一个个执行了。

最后使用target_link_libraries指令将我们的可执行目标程序链接到gtest。

# 将源文件testMathUtils.cpp编译为名为testMathUtils的可执行目标
add_executable(testMathUtils testMathUtils.cpp)
# 在CMake中创建一个名为testMathUtils的测试,如果这里不使用该指令,那么CMake无法发现ut测试
add_test(NAME testMathUtils COMMAND testMathUtils)
# 链接到gtest
target_link_libraries(testMathUtils gtest gtest_main)

四、构建工程

照例,进入到build目录,然后cmake

mkdir build
cd build
cmake ..
make

20230104193522

此时,执行ctest即可跑ut case了
20230104193648

当然了,你可以通过直接点击下面这个Run CTest按钮,获得更好的体验(实际是ctest命令配合一些参数)
20230104193855

点击之后,可以自动为你构建工程并运行ut
20230104194121

现在我们试下把add_test指令注掉,你就会发现CMake不能发现测试用例,报出:

[ctest] No tests were found!!!

20230104194336

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

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

相关文章

FFmpeg 解复用实战

1.封装格式相关函数 avformat_alloc_context()&#xff1a;负责申请一个AVFormatContext结构的内存,并进行简单初始化&#xff0c;这个函数可以不用手动调用&#xff0c;内部会自动调用。 avformat_free_context()&#xff1a;释放该结构里的所有东西以及该结构本身&#xff0…

再学C语言24:分支和跳转——逻辑运算符和条件运算符

一、多重选择else if 功能&#xff1a;在两个以上的语句中作出选择 示例代码&#xff1a; #include <stdio.h> int main(void) {float score;printf("Please enter your score: \n");scanf("%f", &score);if(score < 60)printf("不及…

SSM基础整合

SSM基础整合 文章目录SSM基础整合[toc]SSM基础整合SSM整合流程表现层数据封装设置统一数据返回结果类定义code类优化Controller优化后的返还结果异常处理器异常处理项目异常处理方案项目异常分类处理SSM基础整合 SSM整合流程 创建工程 SSM整合 Spring SpringConfig Configur…

CAS 的使用场景 CAS的ABA问题的优化 以及 synchronized 的三大优化

目录 &#x1f388;专栏链接:多线程相关知识详解 一.什么是CAS 二.CAS最常用的两个场景 Ⅰ.实现原子类 Ⅱ.实现自旋锁 三.CAS的ABA问题 四.优化解决CAS的ABA问题 五.synchronized的优化 Ⅰ.锁升级/锁膨胀 Ⅱ.锁消除 Ⅲ.锁粗化 一.什么是CAS CAS&#xff08;Compar…

p2深度学习基本概念简介下笔记

3. 第 1 讲&#xff1a;深度学习基本概念简介下_哔哩哔哩_bilibili 线性模型太简单&#xff0c;我们需要比较复杂的模型。 不管怎样弄&#xff0c;蓝色描述不出红色的线 强调model bias 无法模拟真实的状况 写出一个有未知参数更复杂的model 观察红色的曲线 &#xff1a;可…

你知道数据在内存中是如何存储的嘛?

&#x1f996;作者&#xff1a;学写代码的恐龙 &#x1f996;博客主页&#xff1a;学写代码的恐龙博客主页 &#x1f996;专栏&#xff1a;【初级c语言】 &#x1f996;语录&#xff1a;❀未来的你&#xff0c;一定会感谢现在努力奋斗的自己❀ 深度剖析数据在内存中的存储一、…

数据结构精讲——排序(二)

数据结构精讲——排序&#xff08;二&#xff09; 排序的分类 上节课我们已经了解过插入排序和选择排序&#xff0c;这节课主要讲的是快排排序&#xff0c;冒泡排序应该都很熟悉&#xff0c;少提一下吧。 冒泡排序 冒泡排序是我们刚接触编程时就学习的排序方法&#xff08;还…

达梦数据库实施、运维与使用经验(一)

一、使用Xshell输入Insert语句&#xff0c;回车执行系统没反应 问题解决思路 查下数据库的活动会话数并登录数据库服务器看数据库的资源负载 select * from v$sessions where stateACTIVE;在数据库Xshell中输入语句查询数据库磁盘是否满了 df -lh上图中的第一个命令是用来查…

C++的IO流

目录 1. 流是什么 2. CIO流 2.1 C标准IO流 2.2 C文件IO流 2.2.1 简单读取文件流 2.2.2 C读取文件巧妙之处 3. stringstream的简单介绍 1. 流是什么 “流”即是流动的意思&#xff0c;是物质从一处向另一处流动的过程&#xff0c;是对一种有序连续且具有方向性的数据&am…

【我的渲染技术进阶之旅】关于OpenGL纹理压缩的相关资料

文章目录一、为啥要了解压缩纹理1.1 为啥要使用压缩纹理1.2 如何自定义压缩纹理以及使用压缩纹理的效果1.2.1 使用压缩纹理节省显存1.2.2 自定义压缩纹理&#xff1a;将压缩好的纹理数据保存在本地1.2.3 使用自定义的压缩纹理1.2.3 示例原理二、纹理压缩相关知识2.0 什么是压缩…

FOLOLane论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2105.13680.pdf 一、论文创新点 主流的车道线检测方法使用语义分割和聚类实现&#xff0c;但像素级的输出存在信息冗余&#xff0c;同时会带来大量噪声。而该论文使用两个分支&#xff0c;一个输出heatmap用于判断像素是否是关键点…

干货 | 初窥 Pytest 测试框架,基础薄弱也能轻松 hold 住

pytest 是一个成熟的全功能Python测试工具&#xff0c;可以帮助您编写更好的程序。它与 python 自带的 unittest 测试框架类似&#xff0c;但 pytest 使用起来更简洁和高效&#xff0c;并且兼容 unittest 框架。pytest 能够支持简单的单元测试和复杂的功能测试&#xff0c;pyte…

java中修改List的对象元素时碰到的坑

坑 case1 case1:Data class Person {Integer age;String name;public Person(Integer age, String name) {this.age age;this.name name;} } List<Person> v1List new ArrayList<>(); v1List.add(new Person(11, "小刚")); v1List.add(new Person(1…

前端基础(五)_运算符(算术运算符、赋值运算符、比较运算符、逻辑运算符、三目运算符、运算符优先级和结合性、数据类型的隐式转换)

一、算术运算符 算术运算符即&#xff1a;加&#xff08;&#xff09;减&#xff08;-&#xff09;乘&#xff08;*&#xff09;除&#xff08;/&#xff09;取余&#xff08;%&#xff09;加加&#xff08;&#xff09;减减&#xff08;–&#xff09; 算术运算符里比较特殊的…

CleanMyMacX软件有哪些优缺点?值不值得下载

CleanMyMac X 2023是一款可靠且功能强大的Mac清洁工具工具&#xff0c;他可以让你随时检查Mac电脑的健康情况&#xff0c;并删除电脑中的垃圾文件&#xff0c;来腾出存储空间&#xff0c;保持Mac系统的整洁。至问世以来&#xff0c;CleanMyMac 系统倍受国内外用户推崇&#xff…

【4】SCI易中期刊推荐——神经科学研究(中科院4区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…

C#使用迷宫地图来模拟新冠疫情的传播速度(一)

国家开始发布疫情放开政策&#xff0c;本人于2022-12-21开始感染并发高烧。 最近才康复。有感于此 我们用初始感染源来影响九宫网格来查看新冠的传播速度 小游戏规则如下&#xff1a; 一个感染源 可以传播附近相邻的8个网格【类似于扫雷】&#xff0c;假如每个感染源一天只…

Vue--》setup、ref、reactive函数使用讲解

目录 setup ref函数 reactive函数 Vue3中的响应式原理 setup Vue3中的一个新的配置项&#xff0c;值为一个函数。组件中所用到的数据、方法等等&#xff0c;均要配置在setup中。setup函数的两种返回值&#xff0c;如下&#xff1a; 若返回一个对象&#xff0c;则对象中的…

使用Docker快速搭建Hfish蜜罐

HFish简介 HFish是一款社区型免费蜜罐&#xff0c;侧重企业安全场景&#xff0c;从内网失陷检测、外网威胁感知、威胁情报生产三个场景出发&#xff0c;为用户提供可独立操作且实用的功能&#xff0c;通过安全、敏捷、可靠的中低交互蜜罐增加用户在失陷感知和威胁情报领域的能…

源码讲解ThreadLocal父子线程通信问题(图+文+源码)

1 缘起 在复习ThreadLocal相关应用的知识&#xff0c; 有一个老生常谈的问题&#xff1a;父子线程通信&#xff0c; 起初&#xff0c;对于父子线程通信&#xff0c;仅了解ThreadLocal无法通过子线程获取线程数据&#xff0c; 并不了解为什么会这样&#xff1f;以及为什么Inher…