【超详细教程】GoogleTest CMake直接构建(无需安装,手把手教程)


作者:小猪快跑

基础数学&计算数学,从事优化领域5年+,主要研究方向:MIP求解器、整数规划、随机规划、智能优化算法。

GoogleTest 可帮助您编写更好的 C++ 测试。GoogleTest 是由测试技术团队开发的测试框架,具有 考虑到 Google 的具体要求和限制。无论您从事以下工作 Linux、Windows 或 Mac,如果您编写 C++ 代码,GoogleTest 可以为您提供帮助。它 支持任何类型的测试,而不仅仅是单元测试。

本文将带你快速上手GoogleTest,无需安装到环境,直接用CMake构建。

如有错误,欢迎指正。如有更好的算法,也欢迎交流!!!——@小猪快跑

相关教程

相关文献

CMake工程构建

首先打开CLion创建新工程:
在这里插入图片描述

CMakeLists.txt(能访问GitHub)

cmake_minimum_required(VERSION 3.25)

project(google_test_example)

set(CMAKE_CXX_STANDARD 20)

set(PROJECT_ROOT_PATH "${PROJECT_SOURCE_DIR}")
# 可以把gtest打包后的.so文件放进lib目录下
set(LIBRARY_OUTPUT_PATH "${PROJECT_ROOT_PATH}/${OUTDIRS}/lib/")
# 可以把输出文件放进bin目录下
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_ROOT_PATH}/${OUTDIRS}/bin/")

# Build GoogleTest dependencies.
set(BUILD_GoogleTest ON)

include(FetchContent)
# 填充期间的日志输出可能非常冗长,使得配置阶段非常嘈杂。此缓存选项(ON默认情况下)隐藏所有填充输出,除非遇到错误。如果遇到挂起下载的问题,
# 暂时关闭此选项可能有助于诊断导致问题的内容群体。
set(FETCHCONTENT_QUIET OFF)

# 避免每次下载编译及其所有依赖
get_filename_component(_deps "../_deps" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
# 在大多数情况下,保存的详细信息没有指定与用于内部子构建、最终源和构建区域的目录相关的任何选项。通常最好将这些决定留给FetchContent 模块来代表项目处理。
# 缓存变量控制收集所有内容填充目录的FETCHCONTENT_BASE_DIR 点,但在大多数情况下,开发人员不需要更改它。
# 默认位置是${CMAKE_BINARY_DIR}/_deps,但如果开发人员更改此值,他们应该致力于保持路径短且刚好低于构建树的顶层,以避免在 Windows 上遇到路径长度问题。
set(FETCHCONTENT_BASE_DIR ${_deps})

# ##############################################################################
# GoogleTest
# ##############################################################################
if (BUILD_GoogleTest)
    message(CHECK_START "Fetching GoogleTest")
    list(APPEND CMAKE_MESSAGE_INDENT "  ")
    FetchContent_Declare(
            googletest
            URL https://github.com/google/googletest/archive/5376968f6948923e2411081fd9372e71a59d8e77.zip
    )
    FetchContent_MakeAvailable(googletest)
    list(POP_BACK CMAKE_MESSAGE_INDENT)
    message(CHECK_PASS "fetched")
endif ()

# Now simply link against gtest or gtest_main as needed. Eg
if (BUILD_GoogleTest)
    add_executable(example src/sample1.h src/sample1.cc src/sample1_unittest.cc)
    target_link_libraries(example gtest_main)
    # add_test(NAME example_test COMMAND example)
endif ()

CMakeLists.txt(不能访问GitHub)

提前下载代码【免费】GoogleTest(gtest)资源-CSDN文库

在这里插入图片描述

cmake_minimum_required(VERSION 3.25)

project(google_test_example)

set(CMAKE_CXX_STANDARD 20)

set(PROJECT_ROOT_PATH "${PROJECT_SOURCE_DIR}")
# 可以把gtest打包后的.so文件放进lib目录下
set(LIBRARY_OUTPUT_PATH "${PROJECT_ROOT_PATH}/${OUTDIRS}/lib/")
# 可以把输出文件放进bin目录下
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_ROOT_PATH}/${OUTDIRS}/bin/")

# Build GoogleTest dependencies.
set(BUILD_GoogleTest ON)

include(FetchContent)
# 填充期间的日志输出可能非常冗长,使得配置阶段非常嘈杂。此缓存选项(ON默认情况下)隐藏所有填充输出,除非遇到错误。如果遇到挂起下载的问题,
# 暂时关闭此选项可能有助于诊断导致问题的内容群体。
set(FETCHCONTENT_QUIET OFF)

# 避免每次下载编译及其所有依赖
get_filename_component(_deps "../_deps" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
# 在大多数情况下,保存的详细信息没有指定与用于内部子构建、最终源和构建区域的目录相关的任何选项。通常最好将这些决定留给FetchContent 模块来代表项目处理。
# 缓存变量控制收集所有内容填充目录的FETCHCONTENT_BASE_DIR 点,但在大多数情况下,开发人员不需要更改它。
# 默认位置是${CMAKE_BINARY_DIR}/_deps,但如果开发人员更改此值,他们应该致力于保持路径短且刚好低于构建树的顶层,以避免在 Windows 上遇到路径长度问题。
set(FETCHCONTENT_BASE_DIR ${_deps})

# ##############################################################################
# GoogleTest
# ##############################################################################
if (BUILD_GoogleTest)
    message(CHECK_START "Fetching GoogleTest")
    list(APPEND CMAKE_MESSAGE_INDENT "  ")
    FetchContent_Declare(
            googletest
            URL "${PROJECT_SOURCE_DIR}/deps/googletest-5376968f6948923e2411081fd9372e71a59d8e77.zip"
    )
    FetchContent_MakeAvailable(googletest)
    list(POP_BACK CMAKE_MESSAGE_INDENT)
    message(CHECK_PASS "fetched")
endif ()

# Now simply link against gtest or gtest_main as needed. Eg
if (BUILD_GoogleTest)
    add_executable(example src/sample1.h src/sample1.cc src/sample1_unittest.cc)
    target_link_libraries(example gtest_main)
    # add_test(NAME example_test COMMAND example)
endif ()

官方测试用例

文件目录如下:

在这里插入图片描述

sample1.cc:

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// A sample program demonstrating using Google C++ testing framework.

#include "sample1.h"

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

  return result;
}

// Returns true if and only if n is a prime number.
bool 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 square 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;
}

sample1.h

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// A sample program demonstrating using Google C++ testing framework.

#ifndef GOOGLETEST_SAMPLES_SAMPLE1_H_
#define GOOGLETEST_SAMPLES_SAMPLE1_H_

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

// Returns true if and only if n is a prime number.
bool IsPrime(int n);

#endif  // GOOGLETEST_SAMPLES_SAMPLE1_H_

sample1_unittest.cc

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// A sample program demonstrating using Google C++ testing framework.

// This sample shows how to write a simple unit test for a function,
// using Google C++ testing framework.
//
// Writing a unit test using Google C++ testing framework is easy as 1-2-3:

// Step 1. Include necessary header files such that the stuff your
// test logic needs is declared.
//
// Don't forget gtest.h, which declares the testing framework.

#include "sample1.h"

#include <limits.h>

#include "gtest/gtest.h"

namespace {

// Step 2. Use the TEST macro to define your tests.
//
// TEST has two parameters: the test case name and the test name.
// After using the macro, you should define your test logic between a
// pair of braces.  You can use a bunch of macros to indicate the
// success or failure of a test.  EXPECT_TRUE and EXPECT_EQ are
// examples of such macros.  For a complete list, see gtest.h.
//
// <TechnicalDetails>
//
// In Google Test, tests are grouped into test cases.  This is how we
// keep test code organized.  You should put logically related tests
// into the same test case.
//
// The test case name and the test name should both be valid C++
// identifiers.  And you should not use underscore (_) in the names.
//
// Google Test guarantees that each test you define is run exactly
// once, but it makes no guarantee on the order the tests are
// executed.  Therefore, you should write your tests in such a way
// that their results don't depend on their order.
//
// </TechnicalDetails>

// Tests Factorial().

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {
  // This test is named "Negative", and belongs to the "FactorialTest"
  // test case.
  EXPECT_EQ(1, Factorial(-5));
  EXPECT_EQ(1, Factorial(-1));
  EXPECT_GT(Factorial(-10), 0);

  // <TechnicalDetails>
  //
  // EXPECT_EQ(expected, actual) is the same as
  //
  //   EXPECT_TRUE((expected) == (actual))
  //
  // except that it will print both the expected value and the actual
  // value when the assertion fails.  This is very helpful for
  // debugging.  Therefore in this case EXPECT_EQ is preferred.
  //
  // On the other hand, EXPECT_TRUE accepts any Boolean expression,
  // and is thus more general.
  //
  // </TechnicalDetails>
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) { EXPECT_EQ(1, Factorial(0)); }

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
  EXPECT_EQ(1, Factorial(1));
  EXPECT_EQ(2, Factorial(2));
  EXPECT_EQ(6, Factorial(3));
  EXPECT_EQ(40320, Factorial(8));
}

// Tests IsPrime()

// Tests negative input.
TEST(IsPrimeTest, Negative) {
  // This test belongs to the IsPrimeTest test case.

  EXPECT_FALSE(IsPrime(-1));
  EXPECT_FALSE(IsPrime(-2));
  EXPECT_FALSE(IsPrime(INT_MIN));
}

// Tests some trivial cases.
TEST(IsPrimeTest, Trivial) {
  EXPECT_FALSE(IsPrime(0));
  EXPECT_FALSE(IsPrime(1));
  EXPECT_TRUE(IsPrime(2));
  EXPECT_TRUE(IsPrime(3));
}

// Tests positive input.
TEST(IsPrimeTest, Positive) {
  EXPECT_FALSE(IsPrime(4));
  EXPECT_TRUE(IsPrime(5));
  EXPECT_FALSE(IsPrime(6));
  EXPECT_TRUE(IsPrime(23));
}
}  // namespace

// Step 3. Call RUN_ALL_TESTS() in main().
//
// We do this by linking in src/gtest_main.cc file, which consists of
// a main() function which calls RUN_ALL_TESTS() for us.
//
// This runs all the tests you've defined, prints the result, and
// returns 0 if successful, or 1 otherwise.
//
// Did you notice that we didn't register the tests?  The
// RUN_ALL_TESTS() macro magically knows about all the tests we
// defined.  Isn't this convenient?

配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

运行后:

D:\CLionProjects\google_test_example\bin\example.exe
Running main() from D:/CLionProjects/google_test_example/_deps/googletest-src/googletest/src/gtest_main.cc
[==========] Running 6 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (6 ms total)


[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (10 ms total)

[----------] Global test environment tear-down
[==========] 6 tests from 2 test suites ran. (26 ms total)
[  PASSED  ] 6 tests.

Process finished with exit code 0

CMake打包gtest.a:

其实通过上述步骤编译后你就会发现多了一个lib目录:

在这里插入图片描述

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CMake是一个跨平台的构建工具,它可以生成Makefile、Visual Studio等不同平台下的构建文件。使用CMake可以有效地进行项目构建,也方便项目的移植。本文将从去除糟粕、重实践、学以致用三方面出发,介绍如何进行CMake的实践应用。 一、去糟粕 在使用CMake之前,我们需要了解一些基本概念,如工程、源码目录、构建目录等。在CMake中,工程一般被定义为一个项目,由多个文件组成,CMake将工程的编译和链接过程整合起来。源码目录是指存放源码的目录,构建目录是指用于存放编译和链接结果的目录。 接着,我们需要了解一些CMake的基本语法。在CMake中,我们可以通过变量、函数、指令等方式来编写脚本。变量用于存储值,函数可重复用于多处代码复用,指令是根据其参数执行特定功能的命令。例如,通过add_executable指令可以创建一个可执行文件。 二、重实践 在使用CMake时,我们需要编写CMakeLists.txt文件来指示CMake如何构建项目。在这个文件中,我们需要指定项目名称、源文件、可执行文件输出路径等信息,然后使用CMake进行构建。 例如,我们可以按照以下步骤来构建一个简单的CMake项目: 1. 创建一个文件夹,作为源码目录和构建目录。 2. 在源码目录中添加CMakeLists.txt文件,编写项目信息。 3. 在源码目录中添加main.cpp文件,用于测试项目。 4. 在终端中,进入构建目录,使用cmake指令生成Makefile等构建文件。 5. 使用make指令进行编译生成可执行文件。 三、学以致用 在实践中,我们还可以使用CMake进行库的构建安装,方便项目的复用和分发。例如,我们可以按照以下步骤来构建安装一个库: 1. 在CMakeLists.txt文件中,通过add_library指令创建库,并指定头文件和源文件。 2. 在终端中,使用cmake指令生成Makefile等构建文件。 3. 使用make指令进行编译生成库文件。 4. 使用make install指令进行安装。 以上就是一个简单的CMake实践过程。通过了解基本语法和操作,我们可以更好地应用CMake构建项目和库。同时,也可以通过阅读官方文档和参考书籍来深入学习CMake的高级功能和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值