Google test的使用
Google test是一种比较方便的C++测试框架,它能够帮助我们比较方便的进行测试代码的编写,以及输出尽可能详细的失败信息。能够大大缩短我们测试代码的编写效率,而且该框架的使用方法也比较简单,能够降低我们学习新框架的负担。
1. googletest的编译安装
1) 安装cmake
# yum install cmake # cmake --version cmake version 2.8.12.2
2) 编译并安装gtest
执行如下命令下载、编译并安装googletest:
# git clone https://github.com/google/googletest.git # ls appveyor.yml BUILD.bazel ci CMakeLists.txt CONTRIBUTING.md googlemock googletest library.json LICENSE platformio.ini README.md WORKSPACE # mkdir mybuild && cd mybuild # cmake .. -- The C compiler identification is GNU 4.8.5 -- The CXX compiler identification is GNU 4.8.5 -- 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 -- 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 -- Found PythonInterp: /usr/bin/python (found version "2.7.5") -- Looking for include file pthread.h -- Looking for include file pthread.h - found -- Looking for pthread_create -- Looking for pthread_create - not found -- 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: /root/googletest/inst/googletest/mybuild # ls bin CMakeCache.txt CMakeFiles cmake_install.cmake CTestTestfile.cmake googlemock googletest lib Makefile
执行完上面的命令后,可以看到生成了相应的编译脚本,接着再执行如下命令完成编译与安装:
# make # make install [ 25%] Built target gtest [ 50%] Built target gmock [ 75%] Built target gmock_main [100%] Built target gtest_main Install the project... -- Install configuration: "" -- Installing: /usr/local/include -- Installing: /usr/local/include/gmock -- Installing: /usr/local/include/gmock/gmock-actions.h -- Installing: /usr/local/include/gmock/gmock-cardinalities.h -- Installing: /usr/local/include/gmock/gmock-function-mocker.h -- Installing: /usr/local/include/gmock/gmock-generated-actions.h -- Installing: /usr/local/include/gmock/gmock-generated-actions.h.pump -- Installing: /usr/local/include/gmock/gmock-generated-function-mockers.h -- Installing: /usr/local/include/gmock/gmock-generated-function-mockers.h.pump -- Installing: /usr/local/include/gmock/gmock-generated-matchers.h -- Installing: /usr/local/include/gmock/gmock-generated-matchers.h.pump -- Installing: /usr/local/include/gmock/gmock-matchers.h -- Installing: /usr/local/include/gmock/gmock-more-actions.h -- Installing: /usr/local/include/gmock/gmock-more-matchers.h -- Installing: /usr/local/include/gmock/gmock-nice-strict.h -- Installing: /usr/local/include/gmock/gmock-spec-builders.h -- Installing: /usr/local/include/gmock/gmock.h -- Installing: /usr/local/include/gmock/internal -- Installing: /usr/local/include/gmock/internal/custom -- Installing: /usr/local/include/gmock/internal/custom/README.md -- Installing: /usr/local/include/gmock/internal/custom/gmock-generated-actions.h -- Installing: /usr/local/include/gmock/internal/custom/gmock-generated-actions.h.pump -- Installing: /usr/local/include/gmock/internal/custom/gmock-matchers.h -- Installing: /usr/local/include/gmock/internal/custom/gmock-port.h -- Installing: /usr/local/include/gmock/internal/gmock-internal-utils.h -- Installing: /usr/local/include/gmock/internal/gmock-port.h -- Installing: /usr/local/include/gmock/internal/gmock-pp.h -- Installing: /usr/local/lib64/libgmock.a -- Installing: /usr/local/lib64/libgmock_main.a -- Installing: /usr/local/lib64/pkgconfig/gmock.pc -- Installing: /usr/local/lib64/pkgconfig/gmock_main.pc -- Installing: /usr/local/lib64/cmake/GTest/GTestTargets.cmake -- Installing: /usr/local/lib64/cmake/GTest/GTestTargets-noconfig.cmake -- Installing: /usr/local/lib64/cmake/GTest/GTestConfigVersion.cmake -- Installing: /usr/local/lib64/cmake/GTest/GTestConfig.cmake -- Installing: /usr/local/include -- Installing: /usr/local/include/gtest -- Installing: /usr/local/include/gtest/gtest-death-test.h -- Installing: /usr/local/include/gtest/gtest-matchers.h -- Installing: /usr/local/include/gtest/gtest-message.h -- Installing: /usr/local/include/gtest/gtest-param-test.h -- Installing: /usr/local/include/gtest/gtest-printers.h -- Installing: /usr/local/include/gtest/gtest-spi.h -- Installing: /usr/local/include/gtest/gtest-test-part.h -- Installing: /usr/local/include/gtest/gtest-typed-test.h -- Installing: /usr/local/include/gtest/gtest.h -- Installing: /usr/local/include/gtest/gtest_pred_impl.h -- Installing: /usr/local/include/gtest/gtest_prod.h -- Installing: /usr/local/include/gtest/internal -- Installing: /usr/local/include/gtest/internal/custom -- Installing: /usr/local/include/gtest/internal/custom/README.md -- Installing: /usr/local/include/gtest/internal/custom/gtest-port.h -- Installing: /usr/local/include/gtest/internal/custom/gtest-printers.h -- Installing: /usr/local/include/gtest/internal/custom/gtest.h -- Installing: /usr/local/include/gtest/internal/gtest-death-test-internal.h -- Installing: /usr/local/include/gtest/internal/gtest-filepath.h -- Installing: /usr/local/include/gtest/internal/gtest-internal.h -- Installing: /usr/local/include/gtest/internal/gtest-param-util.h -- Installing: /usr/local/include/gtest/internal/gtest-port-arch.h -- Installing: /usr/local/include/gtest/internal/gtest-port.h -- Installing: /usr/local/include/gtest/internal/gtest-string.h -- Installing: /usr/local/include/gtest/internal/gtest-type-util.h -- Installing: /usr/local/include/gtest/internal/gtest-type-util.h.pump -- Installing: /usr/local/lib64/libgtest.a -- Installing: /usr/local/lib64/libgtest_main.a -- Installing: /usr/local/lib64/pkgconfig/gtest.pc -- Installing: /usr/local/lib64/pkgconfig/gtest_main.pc
之后将/usr/local/lib64/pkgconfig添加到PKG_CONFIG_PATH中:
# vi /etc/profile export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig/:/usr/local/lib64/pkgconfig/ # source /etc/profile # echo $PKG_CONFIG_PATH :/usr/local/lib/pkgconfig/:/usr/local/lib64/pkgconfig/
2. 测试google test
下面我们编写一个Hello Google Test来进行测试(hello_test.cpp):
执行如下命令进行编译:
# gcc -o hello_test hello_test.cpp -lstdc++ -std=c++11 `pkg-config --cflags --libs gtest` # ./hello_test [==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from FunTest [ RUN ] FunTest.HandlesZeroInput [ OK ] FunTest.HandlesZeroInput (0 ms) [----------] 1 test from FunTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test suite ran. (0 ms total) [ PASSED ] 1 test.
上面可以看到程序运行成功。
3. gtest运行原理
关于gtest的运行原理,我们先来googletest源码中TEST
宏定义的实现:
TEST是一个宏定义,而GTEST_TEST_
也是一个宏,其会根据test_fixture
以及test_name
字符串拼接出一个class name,然后会采用该class生成相应的对象登记到google测试框架中。从而在调用RUN_ALL_TESTS()时就会一个个的执行相应的测试用例。例如:
因为上面每个拼接生成的类都会继承自testing::Test,因此这里提供了另外一个宏定义TEST_F
允许我们对testing::Testing做一些相应的修改,即我们可以通过继承testing::Test来对相应的成员函数进行重载,从而满足一些特定的需求。
4. 断言/宏测试
Google Test采用一系列的断言(assert)来进行代码测试,这些宏有点类似于函数调用。当断言失败时,Google Test将会打印出assertion时的源文件和出错行的位置,以及附加的失败信息,用户可以直接通过<<
在这些断言宏后面跟上自己希望在断言命中时的输出信息。
测试宏可以分为两大类: ASSERT_*
和EXPECT_*
,这些成对的断言功能相同,但效果不同。其中ASSERT_*
将会在失败时产生致命错误并中止当前调用它的函数的执行。EXPECT_*
版本的会生成非致命错误,不会终止当前函数,而是继续执行当前函数。通常情况,应该首选使用EXPECT_*
,因为ASSERT_*
在报告完错误后不会进行清理工作,可能导致内存泄露问题。
- 基本断言
- 二值比较
- 字符串比较
5. 事件机制
1) 全局事件
要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp()和TearDown()方法。
-
Setup()方法在所有案例执行前执行
-
TearDown()方法在所有案例执行后执行
还需要告诉gtest添加这个全局事件,我们需要在main函数中通过testing::AddGlobalTestEnvironment()方法将事件挂进来,也就是说,我们可以写很多个这样的类,然后把它们的事件都挂上去。
2) TestSuit事件
我们需要写一个类,继承testing::Test,然后实现两个静态方法:
-
SetupTestCase()该方法在第一个TestCase之前执行
-
TearDownTestCase()该方法在最后一个TestCase之后执行
在编写测试案例时,我们需要使用TEST_F
这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuit。
3) TestCase事件
TestCase事件是挂在每个案例执行前后的,实现方式和上面的几乎一样,不过需要实现的是Setup()方法和TearDown()方法:
-
Setup()方法在每个TestCase之前执行
-
TearDown()方法在每个TestCase之后执行
以下案例说明上述三个事件的使用:
编译运行:
# gcc -o test test.cpp -lstdc++ -std=c++11 `pkg-config --cflags --libs gtest` # ./test [==========] Running 2 tests from 1 test suite. [----------] Global test environment set-up. Foo FooEnvironment SetUP [----------] 2 tests from TestMap SetUpTestCase() [ RUN ] TestMap.test1 SetUp() is running this is test1 *********** 23 ********** end test1 TearDown() [ OK ] TestMap.test1 (0 ms) [ RUN ] TestMap.test2 SetUp() is running this is test2 *********** 23 ********** end test2 TearDown() [ OK ] TestMap.test2 (1 ms) TearDownTestCase() [----------] 2 tests from TestMap (1 ms total) [----------] Global test environment tear-down Foo FooEnvironment TearDown [==========] 2 tests from 1 test suite ran. (1 ms total) [ PASSED ] 2 tests.
6. 参数化
当考虑多次要为被测函数传入不同的值的情况时,可以按下面的方法去测试。必须添加一个类,继承自testing::TestWithParam
编译运行:
# gcc -o test test.cpp -lstdc++ -std=c++11 `pkg-config --cflags --libs gtest` # ./test [==========] Running 5 tests from 1 test suite. [----------] Global test environment set-up. [----------] 5 tests from TrueReturn/IsPrimeParamTest [ RUN ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/0 [ OK ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/0 (0 ms) [ RUN ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/1 [ OK ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/1 (0 ms) [ RUN ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/2 [ OK ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/2 (0 ms) [ RUN ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/3 [ OK ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/3 (0 ms) [ RUN ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/4 [ OK ] TrueReturn/IsPrimeParamTest.HandleTrueReturn/4 (0 ms) [----------] 5 tests from TrueReturn/IsPrimeParamTest (0 ms total) [----------] Global test environment tear-down [==========] 5 tests from 1 test suite ran. (1 ms total) [ PASSED ] 5 tests.
[参看]