Windows下搭建googletest测试环境 for Qt6
背景
因为需要将CMake构建的项目从VS 2022移植到Qt6,网上找了很多资料,但很少有适用于自己情况的,比如最简单的,通过CMake从网络下载googletest代码到项目,在Qt CMake上无法下载,而在VS 2022上下载、编译完全没有问题. 于是,决定从官网找解决办法.
环境
环境1:
| 工具环境 | 版本 |
|---|---|
| 系统 | Win10x64专业版 |
| IDE | VS 2022 |
| 编译器 | msvc 17.2 |
| 构建工具 | CMake 3.23.1 |
环境2:
| 工具环境 | 版本 |
|---|---|
| 系统 | Win10x64专业版 |
| IDE | Qt 6.5.2 |
| 编译器 | MinGW 11.2.0 64bit |
| 构建工具 | CMake 3.24.2 |
googletest源码包:googletest Release 1.16.0
注意:
- googletest要求CMake使用3.14以后版本,因为后面用到
FetchContent_MakeAvailable()命令; - googletest要求使用C++14以后版本,才能成功编译;
- 用MSVC预编译googletest得到的静态链接库文件(.lib),MinGW不能进行静态链接(MinGW支持.a). 需要在QT中使用MSVC编译器(即始终用同一种编译器),或者预编译得到动态链接库文件(.dll,MinGW也支持),亦或在自己项目中用源码编译googletest;
- 预编译得到的库文件,x64 or x32, debug or release 配置,必须跟自己项目生成的目标保持一致.
CMake构建项目
构建GoogleTest并使用之,就是需要告诉我们的构建系统,在哪可以找到头文件、源文件、库文件.
搭建googletest环境,有2步:
1)作为独立的CMake项目进行编译;
2)集成到客户已有源码的项目.
独立的CMake项目
Step1. 下载源码包并构建编译脚本
- 使用命令行
可从googletest官网下载源码包,也可用Powershell执行下面命令下载,然后生成构建脚本:
git clone https://github.com/google/googletest.git -b v1.16.0
cd googletest # Main directory of the cloned repository.
mkdir build # Create a directory to hold the build output.
cd build
cmake .. # Generate native build scripts for GoogleTest.
上面默认包含了GoogleMock(Mock,基于GoogleTest框架,可用来模拟对象行为). 如果不想要,上面最后一行命令可换为:
cmake .. -DBUILD_GMOCK=OFF
默认是用Debug模式构建,如果想用Release模式,则可执行:
cmake --build . --config Release -v
- 使用CMake-gui
当然,也可用CMake-gui进行这步操作(不一定非得VS 2022编译器):

Configure后,会得到如下结果:

这里可以按需配置编译选项. 如果勾选第二项BUILD_SHARED_LIBS,那么会编译生成动态链接库文件(.dll);否则,默认生成静态库文件(.a).
Step2. 编译、安装(install)到本地目录
编译项目,生成库文件后,需要将头文件、库文件拷贝到本地指定目录,方便不同项目使用.
- 类Unix系统
如果是类Unix系统,可执行命令(需要管理员权限):
make
sudo make install # Install in /usr/local/ by default
- Windows系统
方式一:用VS 2022
如果是Windows系统,且已安装Visual Studio(VS),那么可以直接打开上一步生成的gtest.sln文件或者googletest-distribution.sln,然后用VS进行编译.
注意:如果库的安装路径(CMAKE_INSTALL_PREFIX)位于C盘,那么可能需要管理员权限打开VS.
打开项目后,会得到如下多个目标的解决方案:

到这里,还没有生成库文件(.lib, .dll). 需要右键ALL_BUILD > 生成,为构建生成目标;接着,右键INSTALL > 生成,将头文件、库文件安装到指定目录(默认C:\Program Files (x86)\googletest-distribution).
于是,在库目录可看到安装好的文件:

include/gtest目录头文件:

lib目录库文件(默认选择生成静态链接库文件):

注意:GoogleTest默认生成的Debug模式下的32bit版本库文件. 如果需要修改,可在CMake配置时修改设置,或者编译时指定编译选项,然后在VS 2022中重新生成目标即可.
dll目录库文件(如果选择生成动态链接库文件):

方式二:用命令行
如果不用VS(需要任意一款CMake支持的C++编译器),直接用命令行,也是可以的. Powershell执行命令:
cmake --install .
注意:
-
如果提示"Install cannot find `.../Release/gmock.lib` File exists"(文件未找到)的错误,说明前面以Debug模式构建,而install默认Release模式. 重新以Release模式构建项目即可.
-
如果C盘没有安装文件,可能没有以管理员权限运行Powershell.
集成到现有CMake项目
- 以库和头文件的方式使用GoogleTest
CMake中用find_package查找库文件对应的包,前提是库目录已添加到环境变量PATH中.
find_package(GTest CONFIG REQUIRED)
# or check result after find_package
find_package(GTest)
if (NOT GTest_FOUND)
message(FATAL_ERROR "GTest not found")
endif()
后面就能使用GTest包.
注意:find_package的原理是在搜索路径中搜索PackageNameConfig.cmake文件. 对于GTest包,这个文件名为GTestConfig.cmake. 所以可添加%GOOGLETEST_DIR%\lib\cmake到PATH环境变量. 例如,我添加到PATH的路径是:C:\Program Files (x86)\googletest-distribution\lib\cmake(取决于GoogleTest库实际安装目录).
- 以源码的方式使用GoogleTest
健壮、灵活
有4种方式:
- 将GooglTest源码拷贝到指定位置,然后在用户项目中include该路径即可. 缺点是缺少灵活性,很难持续更新.
- 将GooglTest源码作为项目树的一部分. 最简单,但很难持续更新,一些项目可能不允许这样做.
- 将GoogleTest作为git submodule添加到项目. git submodule持续更新非常方便,但需要联网从第三方服务器下载,而且不是自动完成,可能导致项目使用者的版本不同. git submodule可参见git submodule 使用.
- CMake下载GoogleTest作为构建步骤的一部分. 最简单、灵活的一种方式,但也可能存在不同工具的兼容性问题.
方式1:在Qt 自动生成的googletest项目基础上,修改的CMakeList.txt.
cmake_minimum_required(VERSION 3.14)
project(add LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
enable_testing()
find_package(Threads REQUIRED)
message(STATUS "GOOGLETEST_DIR = $ENV{GOOGLETEST_DIR}")
# use defined instead of testing whether the environment value exists or not directly
if (DEFINED ENV{GOOGLETEST_DIR} AND NOT "$ENV{GOOGLETEST_DIR}" STREQUAL "")
file(TO_CMAKE_PATH "$ENV{GOOGLETEST_DIR}" GOOGLETEST_DIR) # convert Windows-style path to cmake path
else ()
if (NOT "" STREQUAL "")
message(WARNING "Using googletest src dir specified at Qt Creator wizard")
endif ()
set(GOOGLETEST_DIR "")
endif ()
if (EXISTS ${GOOGLETEST_DIR})
# keep same with the actual file path
set(GTestSrc ${GOOGLETEST_DIR}/googletest)
set(GMockSrc ${GOOGLETEST_DIR}/googlemock)
elseif (UNIX AND EXISTS /usr/src/gtest)
set(GTestSrc /usr/src/gtest)
message(WARNING "Using gtest from system")
if (EXISTS /usr/src/gmock)
set(GMockSrc /usr/src/gmock)
endif ()
else ()
message( FATAL_ERROR "No googletest src dir found - set GOOGLETEST_DIR to enable!")
endif ()
set(GTestFiles ${GTestSrc}/src/gtest-all.cc)
set(GTestIncludes ${GTestSrc} ${GTestSrc}/include)
if (NOT ${GMockSrc} STREQUAL "")
list(APPEND GTestFiles ${GMockSrc}/src/gmock-all.cc)
list(APPEND GTestIncludes ${GMockSrc} ${GMockSrc}/include)
endif ()
include_directories(${GTestIncludes})
add_executable(add main.cpp add_test.cpp
${GTestFiles})
add_test(NAME add COMMAND add)
target_link_libraries(add PRIVATE Threads::Threads)
方式2、3:不推荐,不过操作也简单
方式4:推荐的方式,但需要持续联网,而且工具支持
cmake_minimum_required(VERSION 3.14)
...
include(FetchContent)
FetchContent_Declare(
googletest
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/5376968f6948923e2411081fd9372e71a59d8e77.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# Now simply link against gtest or gtest_main as needed. Eg
add_executable(hello main.cpp add_test.cpp)
target_link_libraries(hello gtest_main)
add_test(NAME add_test COMMAND hello)
还有其他的写法,添加检查机制,更加灵活、安全,但本质一样.
cmake_minimum_required(VERSION 3.14)
...
if (NOT googletest) # is googletest defined if already built?
include(FetchContent)
FetchContent_Declare(
googletest
# Specify the commit you depend on and update it regularly.
URL https://github.com/google/googletest/archive/refs/heads/master.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endif()
注意:必须在FetchContent_Declare命令前添加include(FetchContent),而且要求CMake 3.11以上版本;FetchContent_MakeAvailable命令要求CMake 3.14以上版本
测试环境
添加测试文件add_test.cpp
#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
using namespace testing;
int add(int a, int b)
{
return a + b;
}
TEST(Hello, add_test)
{
EXPECT_EQ(1, 1);
ASSERT_THAT(0, Eq(0));
EXPECT_EQ(add(1, 2), 3);
EXPECT_TRUE(add(4, 5) == 9);
}
自动生成的main.cpp文件
#include <gtest/gtest.h>
int main(int argc, char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
编译、运行得到结果:
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from Hello
[ RUN ] Hello.add_test
[ OK ] Hello.add_test (0 ms)
[----------] 1 test from Hello (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
则说明测试用例通过.

浙公网安备 33010602011771号