cmake + googletest 之一 入门

一: 环境

  1. OS: Ubuntu 18.04
  2. CMAKE: 3.14.5
  3. GTest: 1.8.1

注意:

  1. 不涉及如何安装 CMAKE 了, 相信看到这篇文章的你一定已经安装好了.
  2. 假设你已经基本会使用CMAKE 了.
  3. 这个博客并不会介绍GTest 的函数用法.

二: 安装 GTest ( google test )

GTest 的 github 地址: https://github.com/google/googletest

为了稳定性, 一般不直接拉取github 上面的代码, 而是下载 release 标签下的源码压缩包.
当前我看到的最新 release 版本是: 1.8.1.

所以下面的命令是 下载 以及 编译安装 的过程.

# 进入到下载目录
cd ~/Downloads
# 下载最新的release 并保存为 googletest-1.8.1.tar.gz
wget -O googletest-1.8.1.tar.gz https://github.com/google/googletest/archive/release-1.8.1.tar.gz
# 解压
tar -zxf googletest-1.8.1.tar.gz
# 进入解压后的目录
cd googletest-release-1.8.1
# 为编译创建一个目录
mkdir build && cd build
cmake ..
make
# 安装
sudo make install

头文件安装到了 /usr/local/include/gtest/
库文件在 /usr/local/lib/ 下, 它们分别是: libgtest.alibgtest_main.a
还有一些cmake 的模块文件被安装到了你的 cmake 模块目录下.

三: cmake 项目常规测试示例

网上大部分博客都没有给出一个真正能让人弄懂或符合实际项目的示例.
我最先掌握的单元测试是 Java 中的 Maven + JUnit 方式的测试,
我认为大多数的单元测试都应该是那样的目录结构.

所以本示例的项目目录结构如下

├── CMakeLists.txt
├── main.cpp
├── src
│   └── myproject
│       └── myclass.hpp
└── test
    ├── CMakeLists.txt
    └── test_my_class.cpp

我这里将 项目根目录 描述为 / 目录.

/src 为程序源码目录
/test 是测试代码目录


文件 /src/myproject/myclass.hpp 的内容为:

#pragma once

#include 

class my_class
{
public:
    my_class(const std::string& name, int age)
    {
        m_age = age;
        m_name = name;
    }

public:
    int get_age() { return m_age; }
    std::string get_name() { return m_name; }
    
private:
    int m_age;
    std::string m_name;
};

文件 /test/test_my_class.cpp 的内容为:

#include 

#include 

TEST(test_my_class, get_age)
{
    my_class myClass("Joel", 21);
    ASSERT_TRUE(myClass.get_age() == 16) << "age is not 16";
}

TEST(test_my_class, get_name)
{
    my_class myClass("Joel", 21);
    ASSERT_EQ(myClass.get_name(), "Joel") << "name is not Joel";
}

文件 /test/CMakeLists.txt 的内容为:

# 查找 GTest 库
find_package(GTest REQUIRED)
# GTest 的头文件
include_directories(${GTEST_INCLUDE_DIRS})

add_executable(test_my_class test_my_class.cpp)

# 链接测试库
target_link_libraries( test_my_class
        ${GTEST_BOTH_LIBRARIES}
        pthread )

# 添加到测试
gtest_discover_tests(test_my_class)

注意:

target_link_libraries() 里面 link 了 ${GTEST_BOTH_LIBRARIES}, 这个表示链接google test 的两个 库.
GTest 依赖 pthread 库, 所以要链接.
特别提示: pthread 库一定要写在 ${GTEST_BOTH_LIBRARIES} 的后面, 否则编译时会报错,
错误示例如下:

undefined reference to `pthread_getspecific'
undefined reference to `pthread_key_delete'

最初我还以为我没链接 pthread 库, 可是我明明写了的啊 ! 搞了好久才找到问题.


文件 /CMakeLists.txt 的内容为:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

set(CMAKE_CXX_STANDARD 14)

include_directories(${PROJECT_SOURCE_DIR}/src)

# 开启测试
enable_testing()

set(MY_PROJECT_SRC
        src/myproject/myclass.hpp)

add_executable(MyProject
        ${MY_PROJECT_SRC}
        main.cpp )

# 添加测试目录
add_subdirectory(test)

四: 编译与运行测试

我们在项目的根木下新建一个文件夹 build
然后编译:

mkdir build && cd build
cmake ..

以下是 cmake 的输出:

-- The C compiler identification is GNU 7.4.0
-- The CXX compiler identification is GNU 7.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found GTest: /usr/local/lib/libgtest.a  
-- Configuring done
-- Generating done

从倒数第三行可以看到, cmake 已经找到了 GTest 的库文件

然后进行编译

make

cmake 的输出如下:

Scanning dependencies of target MyProject
[ 25%] Building CXX object CMakeFiles/MyProject.dir/main.cpp.o
[ 50%] Linking CXX executable MyProject
[ 50%] Built target MyProject
Scanning dependencies of target test_my_class
[ 75%] Building CXX object test/CMakeFiles/test_my_class.dir/test_my_class.cpp.o
[100%] Linking CXX executable test_my_class
[100%] Built target test_my_class

可以看到, 一共生成了两个文件, 分别是 程序目标文件(MyProject) 和 测试目标文件(test_my_class).

其中 test_my_class 文件在 当前目录下的 test/ 文件夹下, 我们运行它, 看看测试效果.

cd test
./test_my_class

输出结果:

[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from test_my_class
[ RUN      ] test_my_class.get_age
/home/joel/cpp/MyProject/test/test_my_class.cpp:9: Failure
Value of: myClass.get_age() == 16
  Actual: false
Expected: true
age is not 16
[  FAILED  ] test_my_class.get_age (0 ms)
[ RUN      ] test_my_class.get_name
[       OK ] test_my_class.get_name (0 ms)
[----------] 2 tests from test_my_class (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] test_my_class.get_age

 1 FAILED TEST

可以看到一个测试成功一个测试失败, 达到我们的目的了.

五: 接下来

上面的示例可以说是非常的简单了:

  1. 程序的源码只有一个 hpp 文件.
  2. 程序的源码没有链接任何其他库.
  3. 程序的源码中没有包含其他头文件.

当程序结构越来越复杂的时候, 像 /test/CMakeLists.txt 这样的文件写起来就会变得相对的复杂.

当然, 有了这篇博客作为基石, 能运行起来最简单的测试代码之后害怕更复杂的吗?
万事开头难, 网上的教程并不一定符合你的理解能力或者项目实际情况.

你可能感兴趣的:(c++)