单元测试(Unit Test)通常是一小段用于检验某个小功能是否正确的测试代码。通过编写单元测试可以在编码阶段发现程序编码错误,甚至是程序设计错误。
单元测试不但可以增加开发者对于所完成代码的自信,同时,好的单元测试用例往往可以在回归测试的过程中,很好地保证之前所发生的修改没有破坏已有的程序逻辑。因此,单元测试不但不会成为开发者的负担,反而可以在保证开发质量的情况下,加速迭代开发的过程。
GoogleTest是一个由Google公司发布的跨平台、使用C++编写的单元测试框架,是目标较为常用的C++单元测试框架之一。
CMake工程引入googletest框架
利用CMake的FetchContent模块,我们可以方便地在CMake工程引入googletest的源码,在整个工程编译的过程中完成googletest源码下载和编译的操作,无需额外在本地保存源码或预编译二进制库。
相关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 /path/to/googletest_src.tar.gz
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# 不安装googletest库文件
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
googletest具体使用
首先,写一段简单的测试代码,假设代码文件名为hello_test.cpp:
#include <gtest/gtest.h>
TEST(HelloTest, BasicAssertions) {
// Expect equality
EXPECT_EQ(5 * 6, 30);
}
得益于googletest的封装,我们无需在测试代码里编写main()函数。
然后在CMakeLists.txt中构建这段代码成可执行程序,示例如下:
enable_testing()
add_executable(
hello_test
hello_test.cpp
)
target_link_libraries(
hello_test
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(hello_test)
最后,构建整个CMake工程并使用ctest命令运行测试用例:
mkdir build && cd build
cmake ..
cmake --build .
ctest
googletest
在之前的测试代码中,我们使用了EXPECT_EQ()断言,若两个参数不相等,会导致最终测试结果为失败。googletest中还提供了很多断言接口帮助我们验证测试结果,这些断言接口分为两类:
- ASSERT_XXX(): 如果断言失败,测试流程直接终止
- EXPECT_XXX(): 如果断言失败,测试流程继续,但会在最终测试结果里报告该处断言失败
一些常用的断言见下表:
描述 | ASSERT_XXX() | EXPECT_XXX() |
---|---|---|
condition 为真 | ASSERT_TRUE(condition) | EXPECT_TRUE(condition) |
condition 为假 | ASSERT_FALSE(condition) | EXPECT_FALSE(condition) |
相等 | ASSERT_EQ(arg1,arg2) | EXPECT_EQ(arg1,arg2) |
不相等 | ASSERT_NE(arg1,arg2) | EXPECT_NE(arg1,arg2) |
小于 | ASSERT_LT(arg1,arg2) | EXPECT_LT(arg1,arg2) |
小于或等于 | ASSERT_LE(arg1,arg2) | EXPECT_LE(arg1,arg2) |
大于 | ASSERT_GT(arg1,arg2) | EXPECT_GT(arg1,arg2) |
大于或等于 | ASSERT_GE(arg1,arg2) | EXPECT_GE(arg1,arg2) |
C字符串相等 | ASSERT_STREQ(str1,str2) | EXPECT_STREQ(str1,str2) |
C字符串不相等 | ASSERT_STRNE(str1,str2) | EXPECT_STRNE(str1,str2) |
C字符串相等(区分大小写) | ASSERT_STRCASEEQ(str1,str2) | EXPECT_STRCASEEQ(str1,str2) |
C字符串相等(区分大小写 ) | ASSERT_STRCASENE(str1,str2) | EXPECT_STRCASENE(str1,str2) |