gTest - 从源码引入自己的项目[原文来自Raymii.org]
写在前面
这是我在解决搭建gTest测试框架遇到的问题时,偶然遇到的一篇英文博客文章,来自于一位荷兰的博主,他发布在他的个人博客上的。
Hi there! I’m Remy, a developer from The Netherlands with a focus on C++, C, some C#, Linux and embedded systems. I currently work on a C++ and Qt stack running on Yocto Linux. It controls hardware, runs the UI and has a few utilities for IoT connectivity and configuration. Technologies I’m fluid in include C, C# & C++, Windows (MFC/Win32), .NET (Core, Xaml, Framework and C++/CLI), Flash, Qt, Ansible, Bash & PowerShell. I was Linux and UNIX sysadmin for over 10 years before I got into development.
原文链接
获取本文代码
本文的代码,已上传码云gitee,无需逐个复制到文件中。
但是不包含Google Test的源代码。
仓库地址:https://gitee.com/gz2022/google-test-example.git
获取Google Test源码
Google Test作为一款开源软件,是支持从源码构建的。
github源码仓库为https://github.com/google/googletest
如果要求不高的话,也可以在码云gitee上获取,比较方便一些。https://gitee.com/mirrors/googletest
使用下面的git命令可以获取源代码。
git clone https://github.com/google/googletest
git clone https://gitee.com/mirrors/googletest
Google Test官方文档中的构建方式
Google Test的官方文档中,有Quickstart: Building with CMake章节,里面介绍了一种通过CMake构建的方式。
其核心部分是编写如下内容的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.14)
project(my_project)
# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
这个方法我调试未成功,猜测主要原因在于
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
这一行。需要连接到github自行下载Google Test源码并且构建。
但是连接github有时候比较麻烦。
其实通过其他途径,获取源代码并不困难,只是需要构建而已。build的过程万变不离其宗,应该还是有其他方案的,哪怕原始一些。
Raymii.org博客中的示例工程
然后我在搜索的过程中,就找到了Raym的博客。他没有使用官方文档中的方式。
我们先来跟随着Raym的脚步来从头开始构建一个项目。
他的文章中,假设我们有这样一个项目,需要使用gTest进行测试,项目文件名为ExampleProject
,其中包含build
,lib
,src
和tst
(short for test
)4个子文件夹。以及根目录下的CMakeLists.txt
文件。
项目的代码主要由3个文件组成,Formula.cpp
,Formula.h
,main.cpp
。
build
:用于构建的文件夹lib
:存储项目的其他依赖库,这里只存储了用于测试的gTestsrc
:项目的源代码Formula.cpp
,Formula.h
,main.cpp
:待测的项目代码CMakeLists.txt
:src
文件夹下的CMakeLists文件
tst
:项目测试代码Formula-test.cpp
:对Formula类的测试代码,通过命名规范来清晰地实现项目和测试的分离。main.cpp
:测试项目的主函数CMakeLists.txt
:tst
文件夹下的CMakeLists文件
$ tree -L 2 ExampleProject/
ExampleProject/
|-- build/
|-- CMakeLists.txt
|-- lib/
| `-- googletest
|-- src/
| |-- CMakeLists.txt
| |-- Formula.cpp
| |-- Formula.h
| `-- main.cpp
`-- tst/
|-- CMakeLists.txt
|-- Formula-test.cpp
`-- main.cpp
将整个google test项目的源代码,都拷贝到lib
文件夹下的googletest
中。从下面的实例可以看出,googletest
文件夹下面就是gTest仓库中的所有内容。内容可能有所不同,因为这个terminal信息是我已经build之后的样子,可能会多出一些文件。
user@ubuntu:~/cpp_workspace/GoogleTestExample/lib$ cd googletest/
user@ubuntu:~/cpp_workspace/GoogleTestExample/lib/googletest$ ls
build CMakeLists.txt docs googletest LICENSE WORKSPACE
BUILD.bazel CONTRIBUTING.md fake_fuchsia_sdk.bzl googletest_deps.bzl MODULE.bazel WORKSPACE.bzlmod
ci CONTRIBUTORS googlemock install README.md
项目各个文件中的内容
各级CMakeLists.txt
根目录下CMakeLists.txt的内容
项目的名称是ExampleProject
,通过project()
语句来指定。
cmake_minimum_required(VERSION 3.10)
project(ExampleProject)
set(CMAKE_CXX_STANDARD 14)
include_directories(src)
add_subdirectory(src)
add_subdirectory(tst)
add_subdirectory(lib/googletest)
src文件夹下CMakeLists.txt的内容
根据cmake变量${CMAKE_PROJECT_NAME}
获取项目的名称(由project()
语句指定了的),并通过set()
语句赋值给变量${BINARY}
。
这里的
file()
语句我也没看懂,但是他能起到的作用就是把当前目录下的所有*.h
和*.cpp
文件都添加到一个${SOURCES}
变量中。
set(BINARY ${CMAKE_PROJECT_NAME})
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES ${SOURCES})
add_executable(${BINARY}_run ${SOURCES})
add_library(${BINARY}_lib STATIC ${SOURCES})
tst文件夹下CMakeLists.txt的内容
与src
文件夹相比,区别是多了一个target_link_libraries()
语句。
测试代码需要依赖于库${CMAKE_PROJECT_NAME}_lib
,而由前文可知,${BINARY}_lib
就是${CMAKE_PROJECT_NAME}_lib
(根据set(BINARY ${CMAKE_PROJECT_NAME})
)。也就是说,原项目中构建了一个库(而且是静态库),供测试代码在构建时使用。
set(BINARY ${CMAKE_PROJECT_NAME}_tst)
file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.h *.cpp)
set(SOURCES ${TEST_SOURCES})
add_executable(${BINARY} ${TEST_SOURCES})
add_test(NAME ${BINARY} COMMAND ${BINARY})
target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest)
项目的源代码
src/main.cpp
#include <iostream>
#include "Formula.h"
int main() {
std::cout << "Bla: " << Formula::bla(2) << std::endl;
return 0;
}
src/Formula.h
Formula
类定义了一个静态方法,传入一个整数,返回这个整数的2倍。
#ifndef EXAMPLEPROJECT_FORMULA_H
#define EXAMPLEPROJECT_FORMULA_H
class Formula {
public:
static int bla(int arg1);
};
#endif //EXAMPLEPROJECT_FORMULA_H
src/Formula.cpp
#include "Formula.h"
int Formula::bla(int arg1) {
return arg1 * 2;
}
测试程序的源代码
tst/main.cpp
#include "gtest/gtest.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
tst/Formula-test.cpp
#include "gtest/gtest.h"
#include "Formula.h"
TEST(blaTest, test1) {
//arrange
//act
//assert
EXPECT_EQ (Formula::bla (0), 0);
EXPECT_EQ (Formula::bla (10), 20);
EXPECT_EQ (Formula::bla (50), 100);
}
构建并运行测试
进入build
文件夹,并按照cmake的常用操作进行构建
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles"
make all
构建出的二进制程序,就在build
文件夹下,使用find
命令可以查找出来。(下面还有一些中间文件)
user@ubuntu:~/cpp_workspace/GoogleTestExample/build$ find . -executable -type f
./src/GoogleTestExample_run
./CMakeFiles/3.16.3/CompilerIdC/a.out
./CMakeFiles/3.16.3/CompilerIdCXX/a.out
./CMakeFiles/3.16.3/CMakeDetermineCompilerABI_C.bin
./CMakeFiles/3.16.3/CMakeDetermineCompilerABI_CXX.bin
./test/GoogleTestExample_tst
运行项目程序
运行
./src/ExampleProject_run
输出
Bla: 4
运行测试程序
运行
./test/GoogleTestExample_tst
输出
user@ubuntu:~/cpp_workspace/GoogleTestExample/build$ ./test/GoogleTestExample_tst
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from blaTest
[ RUN ] blaTest.test1
[ OK ] blaTest.test1 (0 ms)
[----------] 1 test from blaTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
至此,一个完整的利用gTest对项目代码进行测试的流程已经结束了。
- gTest是以第三方库的形式参与到项目之中的。
- 测试代码与原工程的代码也是分离的。