C++ projects use CMake and Google Test (a dumb tutorial)

This guide will show you how to set up a new C++ project using CMake and unit testing through Google's testing framework. With this setting, you can immediately start using C++ for test-driven development. It is also easy to figure out how to add gtest to an existing project and start doing TDD on the old (existing) code base.

Environment: win10 subsystem linux ubuntu18.04

Make sure you have installed cmake (above 3.10), g++, gcc and other basic environments.

The final rendering:

Clone the google test source code from github

git clone https://github.com/google/googletest/

The gtest project contains CMakeLists.txt, so it is relatively simple to integrate into your own project (if you know cmake, if you don’t, just follow this guide.

File structure

IndexProject
├── CMakeLists.txt
├── build
├── lib
│   └── googletest
├── src
│   ├── CMakeLists.txt
│   ├── Formula.cpp
│   ├── Formula.h
│   └── main.cpp
└── tst
    ├── CMakeLists.txt
    ├── Formula-test.cpp
    └── main.cpp

The following command is to create this directory structure

mkdir -p IndexProject/{build,lib,src,tst}

Put the cloned gooletest folder into the lib folder of the project.

It should be no problem for most of the simple projects of individuals to use the above directory structure, so this is equivalent to a template for your future and other novices' reference. The best way is of course to learn CMake, and then do whatever you want. CMake can take time to figure it out. This template is a good choice for people who are pressed for time.

CMakeLists.txt

There are two ways to generate targets. One is to list the file names one by one. The advantage of this is that there is no need to compile unnecessary files.

add_executable(ExampleProject main.cpp file1.cpp file1.h)

The other is to compile all the files and then generate an executable file. The advantage of this is that you can run it directly without modifying the CMakeLists.txt after adding files.

file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)

CMakeLists.txt in the root directory

# cmake version
cmake_minimum_required(VERSION 3.10)
# project name
project(IndexProject)
#采用c++14标准
set(CMAKE_CXX_STANDARD 14)

include_directories(src)

add_subdirectory(src)
add_subdirectory(tst)
add_subdirectory(lib/googletest)

The include_directories(src) here is to make the header files under src globally visible.

CMakeLists.txt in the src directory

#设置 BINARY 为项目名IndexProject
set(BINARY ${CMAKE_PROJECT_NAME})

# 1
# add_executable(ExampleProject main.cpp file1.cpp file1.h)

# 2
file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES ${SOURCES})
add_executable(${BINARY}_run ${SOURCES})
# 为了让单元测试的时候src下的代码能被作为静态链接库使用
add_library(${BINARY}_lib STATIC ${SOURCES})

CMakeLists.txt in the tst directory

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})
# 链接src生成的lib库和gtest库
target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest)

Add source code

src/main.cpp:

#include <iostream>
#include "Formula.h"

int main() {
    std::cout << "Bla: " << Formula::bla(2) << std::endl;
    return 0;
}

src/Formula.h

#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;
}

Add test code

tst/main.cpp

#include "gtest/gtest.h"

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

The above file will execute all test cases of all test files in the tst directory, only one is added here.

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 (2), 4); //通过
    EXPECT_EQ (Formula::bla (4), 6); //不通过
}

Compile

cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug

Output

-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PythonInterp: /usr/bin/python3.6 (found version "3.6.9")
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /d/code/IndexProject/build
 

Then use make to compile and generate what we need, you can use

make all

Generate all of them.

Output

Scanning dependencies of target IndexProject_lib
[  5%] Building CXX object src/CMakeFiles/IndexProject_lib.dir/Formula.cpp.o
[ 11%] Building CXX object src/CMakeFiles/IndexProject_lib.dir/main.cpp.o
[ 17%] Linking CXX static library libIndexProject_lib.a
[ 17%] Built target IndexProject_lib
Scanning dependencies of target IndexProject_run
[ 23%] Building CXX object src/CMakeFiles/IndexProject_run.dir/Formula.cpp.o
[ 29%] Building CXX object src/CMakeFiles/IndexProject_run.dir/main.cpp.o
[ 35%] Linking CXX executable IndexProject_run
[ 35%] Built target IndexProject_run
Scanning dependencies of target gtest
[ 41%] Building CXX object lib/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[ 47%] Linking CXX static library ../../libgtestd.a
[ 47%] Built target gtest
Scanning dependencies of target IndexProject_tst
[ 52%] Building CXX object tst/CMakeFiles/IndexProject_tst.dir/Formula-test.cpp.o
[ 58%] Building CXX object tst/CMakeFiles/IndexProject_tst.dir/main.cpp.o
[ 64%] Linking CXX executable IndexProject_tst
[ 64%] Built target IndexProject_tst
Scanning dependencies of target gmock
[ 70%] Building CXX object lib/googletest/googlemock/CMakeFiles/gmock.dir/src/gmock-all.cc.o
[ 76%] Linking CXX static library ../../libgmockd.a
[ 76%] Built target gmock
Scanning dependencies of target gmock_main
[ 82%] Building CXX object lib/googletest/googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[ 88%] Linking CXX static library ../../libgmock_maind.a
[ 88%] Built target gmock_main
Scanning dependencies of target gtest_main
[ 94%] Building CXX object lib/googletest/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[100%] Linking CXX static library ../../libgtest_maind.a
[100%] Built target gtest_main

Here is also generated gmock, which is another project under googletest, if you don’t want to generate them, you can also use the following command to generate what we want:

make IndexProject_tst;make IndexProject_run
[ 12%] Building CXX object src/CMakeFiles/IndexProject_lib.dir/Formula.cpp.o
[ 25%] Building CXX object src/CMakeFiles/IndexProject_lib.dir/main.cpp.o
[ 37%] Linking CXX static library libIndexProject_lib.a
[ 37%] Built target IndexProject_lib
[ 50%] Building CXX object lib/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[ 62%] Linking CXX static library ../../libgtestd.a
[ 62%] Built target gtest
[ 75%] Building CXX object tst/CMakeFiles/IndexProject_tst.dir/Formula-test.cpp.o
[ 87%] Building CXX object tst/CMakeFiles/IndexProject_tst.dir/main.cpp.o
[100%] Linking CXX executable IndexProject_tst
[100%] Built target IndexProject_tst
[ 33%] Building CXX object src/CMakeFiles/IndexProject_run.dir/Formula.cpp.o
[ 66%] Building CXX object src/CMakeFiles/IndexProject_run.dir/main.cpp.o
[100%] Linking CXX executable IndexProject_run
[100%] Built target IndexProject_run

Find the executable file we generated

$ find . -executable -type f -name "IndexProject*"
./src/IndexProject_run
./tst/IndexProject_tst

carried out

$ ./src/IndexProject_run;./tst/IndexProject_tst
Bla: 4
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from blaTest
[ RUN      ] blaTest.test1
/d/code/IndexProject/tst/Formula-test.cpp:9: Failure
Expected equality of these values:
  Formula::bla(4)
    Which is: 8
  6
[  FAILED  ] blaTest.test1 (1 ms)
[----------] 1 test from blaTest (2 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (3 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] blaTest.test1

 1 FAILED TEST

This guide mainly refers to a foreign blog. If you want to read the original content, click here . It took a long time to find a blog that you can understand. After reading it for a long time, cmake still didn't understand it too much. You can only understand this kind of foolish. The tutorial is haha. If there are any errors or omissions in the above blog, please private message or view the original text directly. I just tried it myself according to that blog.

 

Guess you like

Origin blog.csdn.net/Fei20140908/article/details/104344462