上一篇文章,我们介绍了CMake:传送门
这一篇文章我暂时不打算继续写CMake相关的东西了,转而写一个叫TDD的开发理论,当然,理论是需要实践支撑的,利用CMake,我简单搭了一个gtest环境。
准备
gtest
Gtest是一个跨平台的(Linux、Mac OS X、Windows、Cygwin、Windows CE and Symbian) C++单元测试框架,由google公司发布。gtest是为在不同平台上为编写C++测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。
简而言之:Gtest测试框架可以在不同平台上为编写C++测试。
可以从以下途径下载gtest:
GitHub:https://github.com/google/googletest
Gitee国内镜像:https://gitee.com/mirrors/googletest
将代码 git clone 到本地,接下来需要编译gtest动态链接库,进入项目文件夹下的googletest根目录,如下:
Directory: D:\toolsSpace\googletest\googletest
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2022/9/17 星期六 19:46 bin
d---- 2022/9/17 星期六 18:51 cmake
d---- 2022/9/17 星期六 19:46 CMakeFiles
d---- 2022/9/17 星期六 18:51 docs
d---- 2022/9/17 星期六 18:51 include
d---- 2022/9/17 星期六 19:46 lib
d---- 2022/9/17 星期六 18:51 samples
d---- 2022/9/17 星期六 18:51 src
d---- 2022/9/17 星期六 18:51 test
-a--- 2022/9/17 星期六 19:45 1609 cmake_install.cmake
-a--- 2022/9/17 星期六 19:45 18571 CMakeCache.txt
-a--- 2022/9/17 星期六 19:44 12322 CMakeLists.txt
-a--- 2022/9/17 星期六 19:45 6889 Makefile
-a--- 2022/9/17 星期六 18:51 9107 README.md
默认是不编译dll动态库的。修改这个目录下的CMakeLists.txt,找到下面这部分:
# These commands only run if this is the main project
if(CMAKE_PROJECT_NAME STREQUAL "gtest" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution")
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
# make it prominent in the GUI.option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)else()mark_as_advanced(
gtest_force_shared_crt
gtest_build_tests
gtest_build_samples
gtest_disable_pthreads
gtest_hide_internal_symbols)endif()
修改option后面的
OFF
为
ON
,代表开启了编译DLL动态库。
Windows默认使用MSVC编译,就是我上篇文章提到的调用VS的部分。执行下面命令以使用MinGW gcc编译:
cmake -G "MinGW Makefiles"
此处可能会报下面的错:
访问127~129:
cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)set_target_properties(gtest PROPERTIES VERSION ${GOOGLETEST_VERSION})cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
很明显没有定义
GOOGLETEST_VERSION
的值,在开头加入
set(GOOGLETEST_VERSION 1.11.0)
即可
编译后执行mingw32的mingw32-make命令
mingw32-make
此时,googletest文件夹下新生成一个bin文件夹,包含libgtest.dll、libgtest_main.dll,这两个文件就是我们需要链接的。
搭建
最后成型的结构如下:
DateTestMy
├─ CMakeLists.txt
├─ gtest
│ ├─ include
│ │ └─ gtest
│ │ ├─ gtest-assertion-result.h
│ │ ├─ gtest-death-test.h
│ │ ├─ gtest-matchers.h
│ │ ├─ gtest-message.h
│ │ ├─ gtest-param-test.h
│ │ ├─ gtest-printers.h
│ │ ├─ gtest-spi.h
│ │ ├─ gtest-test-part.h
│ │ ├─ gtest-typed-test.h
│ │ ├─ gtest.h
│ │ ├─ gtest_pred_impl.h
│ │ ├─ gtest_prod.h
│ │ └─ internal
│ │ ├─ custom
│ │ │ ├─ gtest-port.h
│ │ │ ├─ gtest-printers.h
│ │ │ ├─ gtest.h
│ │ │ └─ README.md
│ │ ├─ gtest-death-test-internal.h
│ │ ├─ gtest-filepath.h
│ │ ├─ gtest-internal.h
│ │ ├─ gtest-param-util.h
│ │ ├─ gtest-port-arch.h
│ │ ├─ gtest-port.h
│ │ ├─ gtest-string.h
│ │ └─ gtest-type-util.h
│ ├─ lib
│ │ ├─ libgtest.dll
│ │ └─ libgtest_main.dll
│ └─ src
│ ├─ gtest-all.cc
│ ├─ gtest-assertion-result.cc
│ ├─ gtest-death-test.cc
│ ├─ gtest-filepath.cc
│ ├─ gtest-internal-inl.h
│ ├─ gtest-matchers.cc
│ ├─ gtest-port.cc
│ ├─ gtest-printers.cc
│ ├─ gtest-test-part.cc
│ ├─ gtest-typed-test.cc
│ ├─ gtest.cc
│ └─ gtest_main.cc
├─ include
│ └─ datet.h
├─ libgtest.dll
├─ libgtest_main.dll
├─ README.md
├─ src
│ └─ datet.cpp
└─ test
└─ datet_unittest.cpp
首先创建工程目录,切换到工程目录下。
- 新建
include、src、test
分别放头文件、代码实现和测试函数。 - 新建gtest文件夹,将googletest的
include、src
直接挪过来。在gtest下建立lib文件夹,放之前编译出来的libgtest.dll
和libgtest_main.dll
。这两个文件在项目根目录也要复制一份,不然编译出来的exe文件会提示缺dll。 - 在工程根目录建立
CMakeLists.txt
代码
一切准备就绪,现在开始编写
CMakeLists.txt
,我的如下:
# 指定CMake编译最低要求版本
cmake_minimum_required(VERSION 3.14)
# 给项目命名
project(datet)
# 指定.h头文件目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/gtest/include
)
# 指定.dll链接库文件目录
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/gtest/lib)
# 收集c/c++文件并赋值给变量
# ${CMAKE_CURRENT_SOURCE_DIR}代表CMakeLists.txt当前项目录
file(GLOB
SRC_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
)
file(GLOB
SRC_TEST_FILES
${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp
)
# 将c文件生成可执行文件sample1.exe
add_executable(${PROJECT_NAME} ${SRC_FILES} ${SRC_TEST_FILES})
# 指定链接库libgtest.dll、libgtest_main.dll
target_link_libraries(${PROJECT_NAME} gtest pthread)
每一项我都写了注释,实际使用时按自己项目内容修改。
我计划用一道很简单的LeetCode题目讲解TDD,题目如下(LeetCode 1154):
输入某年某月某日,判断这一天是这一年的第几天?。 测试用例有多组,注意循环输入
输入描述: 输入多行,每行间隔分割,分别是年,月,日 输出描述: 成功:返回outDay输出计算后的第几天; 失败:返回-1
示例: 输入 2012 12 31 输出 366
这题正常做起来其实非常简单,但是我计划用TDD的思想来完成。
首先是
include\datet.h
intcalculateDate(int year,int month,int day);
然后是
src\datet.cpp
#include"datet.h"intcalculateDate(int year,int month,int day){return1;}
src下的cpp文件应当引用h文件,最后是
test\datet_unittest.cpp
。你可能会对函数内容有疑问,请保持疑问,继续读下去。
#include"gtest/gtest.h"#include"datet.h"TEST(dayFirstTest,dayFirst){EXPECT_EQ(calculateDate(2022,1,1),1);}intmain(int argc,char**argv){
testing::InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();}
main函数相关内容用于初始化gtest,基本不需要更改。
这里我写了一个简单的测试用例,测试case为dayFirstTest,name为dayFirst。其实一眼就能看出百分百通过测试的,而且换个数肯定通不过,但不要着急。
运行
首先是构建
cmake -G "MinGW Makefiles"
结果如图:
接着编译
mingw32-make
结果如下:执行datet.exe,回车,即可看到测试结果:
这个测试我们通过了,这是显而易见的。但其实换个测试用例就大概率过不了。TDD的思想就在于,由测试引导开发,因为有不过的测试用例,所以需要对应修改代码,再重构,再编写新的不过的测试用例,如此循环,直到所有的测试用例全通过为止。
我将在下一篇文章介绍TDD。
版权归原作者 bluebonnet27 所有, 如有侵权,请联系我们删除。