如何用googletest写单元测试_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > 如何用googletest写单元测试

如何用googletest写单元测试

 2012/3/13 15:32:18  russelltao  程序员俱乐部  我要评论(6)
  • 摘要:googletest是一个用来写C++单元测试的框架,它是跨平台的,可应用在windows、linux、Mac等OS平台上。下面,我来说明如何使用最新的1.6版本gtest写自己的单元测试。本文包括以下几部分:1、获取并编译googletest(以下简称为gtest);2、如何编写单元测试用例;3、如何执行单元测试。4、googletest内部是如何执行我们的单元测试用例的。1.获取并编译gtestgtest试图跨平台,理论上,它就应该提供多个版本的binary包。但事实上
  • 标签:Google 测试

googletest是一个用来写C++单元测试的框架,它是跨平台的,可应用在windows、linux、Mac等OS平台上。下面,我来说明如何使用最新的1.6版本gtest写自己的单元测试。

本文包括以下几部分:1、获取并编译googletest(以下简称为gtest);2、如何编写单元测试用例;3、如何执行单元测试。4、google test内部是如何执行我们的单元测试用例的。


1. 获取并编译gtest

gtest试图跨平台,理论上,它就应该提供多个版本的binary包。但事实上,gtest只提供源码和相应平台的编译方式,这是为什么呢?google的解释是,我们在编译出gtest时,有些独特的工程很可能希望在编译时加许多flag,把编译的过程下放给用户,可以让用户更灵活的处理。这个仁者见仁吧,反正也是免费的BSD权限。


源码的获取地址:http://code.google.com/p/googletest/downloads/list


目前gtest提供的是1.6.0版本,我们看看与以往版本1.5.0的区别:

?

[cpp] view plaincopy
    class="dp-cpp">
  1. Changes?for?1.6.0:??
  2. ??
  3. *?New?feature:?ADD_FAILURE_AT()?for?reporting?a?test?failure?at?the??
  4. ??given?source?location?--?useful?for?writing?testing?utilities.??
  5. 。。。?。。。??
  6. *?Bug?fixes?and?implementation?clean-ups.??
  7. *?Potentially?incompatible?changes:?disables?the?harmful?'make?install'??
  8. ??command?in?autotools.??

?

就是最下面一行,make install禁用了,郁闷了吧?UNIX的习惯编译方法:./configure;make;make install失灵了,只能说google比较有种,又开始挑战用户习惯了。

那么怎么编译呢?

先进入gtest目录(解压gtest.zip包过程就不说了),执行以下两行命令:

?

[cpp]?view plaincopy
  1. g++?-I./include?-I./?-c?./src/gtest-all.cc??
  2. ar?-rv?libgtest.a?gtest-all.o??

之后,生成了libgtest.a,这个就是我们要的东东了。以后写自己的单元测试,就需要libgtest.a和gtest目录下的include目录,所以,这1文件1目录我们需要拷贝到自己的工程中。

?

编译完成后怎么验证是否成功了呢?(相当不友好!)

?

[cpp]?view plaincopy
  1. cd?${GTEST_DIR}/make??
  2. ??make??
  3. ??./sample1_unittest??

如果看到:

?

?

[cpp]?view plaincopy
  1. Running?main()?from?gtest_main.cc??
  2. [==========]?Running?6?tests?from?2?test?cases.??
  3. [----------]?Global?test?environment?set-up.??
  4. [----------]?3?tests?from?FactorialTest??
  5. [?RUN??????]?FactorialTest.Negative??
  6. [???????OK?]?FactorialTest.Negative?(0?ms)??
  7. [?RUN??????]?FactorialTest.Zero??
  8. [???????OK?]?FactorialTest.Zero?(0?ms)??
  9. [?RUN??????]?FactorialTest.Positive??
  10. [???????OK?]?FactorialTest.Positive?(0?ms)??
  11. [----------]?3?tests?from?FactorialTest?(0?ms?total)??
  12. ??
  13. [----------]?3?tests?from?IsPrimeTest??
  14. [?RUN??????]?IsPrimeTest.Negative??
  15. [???????OK?]?IsPrimeTest.Negative?(0?ms)??
  16. [?RUN??????]?IsPrimeTest.Trivial??
  17. [???????OK?]?IsPrimeTest.Trivial?(0?ms)??
  18. [?RUN??????]?IsPrimeTest.Positive??
  19. [???????OK?]?IsPrimeTest.Positive?(0?ms)??
  20. [----------]?3?tests?from?IsPrimeTest?(0?ms?total)??
  21. ??
  22. [----------]?Global?test?environment?tear-down??
  23. [==========]?6?tests?from?2?test?cases?ran.?(0?ms?total)??
  24. [??PASSED??]?6?tests.??

那么证明编译成功了。

?


2、如何编写单元测试用例

以一个例子来说。我写了一个开地址的哈希表,它有del/get/add三个主要方法需要测试。在测试的时候,很自然,我只希望构造一个哈希表对象,对之做许多种不同组合的操作,以验证三个方法是否正常。所以,gtest提供的TEST方式我不会用,因为多个TEST不能共享同一份数据,而且还有初始化哈希表对象的过程呢。所以我用TEST_F方式。

??

上面是我要执行单元测试的类图。那么,我需要写一系列单元测试用例来测试这个类。用gtest,首先要声明一个类,继承自gtest里的Test类:

??

代码很简单:

?

[cpp]?view plaincopy
  1. class?CHashTableTest?:?public?::testing::Test?{??
  2. protected:??
  3. ????CHashTableTest():ht(100){??
  4. ??
  5. ????}??
  6. ????virtual?void?SetUp()?{??
  7. ????????key1?=?"testkey1";??
  8. ????????key2?=?"testkey2";??
  9. ????}??
  10. ??
  11. ????//?virtual?void?TearDown()?{}??
  12. ????CHashTable?ht;??
  13. ??
  14. ????string?key1;??
  15. ????string?key2;??
  16. };??


?

然后开始写测试用例,用例里可以直接使用上面类中的成员。

??

[cpp]?view plaincopy
  1. TEST_F(CHashTableTest,?hashfunc)??
  2. {??
  3. ????CHashElement?he;??
  4. ??
  5. ????ASSERT_NE(\??
  6. ????????????ht.getHashKey((char*)key1.c_str(),?key1.size(),?0),\??
  7. ????????????ht.getHashKey((char*)key2.c_str(),?key2.size(),?0));??
  8. ??
  9. ????ASSERT_NE(\??
  10. ????????????ht.getHashKey((char*)key1.c_str(),?key1.size(),?0),\??
  11. ????????????ht.getHashKey((char*)key1.c_str(),?key1.size(),?1));??
  12. ??
  13. ????ASSERT_EQ(\??
  14. ????????????ht.getHashKey((char*)key1.c_str(),?key1.size(),?0),\??
  15. ????????????ht.getHashKey((char*)key1.c_str(),?key1.size(),?0));??
  16. }??

注意,TEST_F宏会直接生成一个类,这个类继承自上面我们写的CHashTableTest类。

?

gtest提供ASSERT_和EXPECT_系列的宏,用于判断二进制、字符串等对象是否相等、真假等等。这两种宏的区别是,ASSERT_失败了不会往下执行,而EXPECT_会继续。


3、如何执行单元测试

首先,我们自己要有一个main函数,函数内容非常简单:

?

[cpp]?view plaincopy
  1. #include?"gtest/gtest.h"??
  2. ??
  3. int?main(int?argc,?char**?argv)?{??
  4. ????testing::InitGoogleTest(&argc,?argv);??
  5. ??
  6. ????//?Runs?all?tests?using?Google?Test.??
  7. ????return?RUN_ALL_TESTS();??
  8. }??

InitGoogleTest会解析参数。RUN_ALL_TESTS会把整个工程里的TEST和TEST_F这些函数全部作为测试用例执行一遍。

?


执行时,假设我们编译出的可执行文件叫unittest,那么直接执行./unittest就会输出结果到屏幕,例如:

?

[cpp]?view plaincopy
  1. [==========]?Running?4?tests?from?1?test?case.??
  2. [----------]?Global?test?environment?set-up.??
  3. [----------]?4?tests?from?CHashTableTest??
  4. [?RUN??????]?CHashTableTest.hashfunc??
  5. [???????OK?]?CHashTableTest.hashfunc?(0?ms)??
  6. [?RUN??????]?CHashTableTest.addget??
  7. [???????OK?]?CHashTableTest.addget?(0?ms)??
  8. [?RUN??????]?CHashTableTest.add2get??
  9. testCHashTable.cpp:79:?Failure??
  10. Value?of:?getHe->m_pNext==NULL??
  11. ??Actual:?true??
  12. Expected:?false??
  13. [??FAILED??]?CHashTableTest.add2get?(1?ms)??
  14. [?RUN??????]?CHashTableTest.delget??
  15. [???????OK?]?CHashTableTest.delget?(0?ms)??
  16. [----------]?4?tests?from?CHashTableTest?(1?ms?total)??
  17. ??
  18. [----------]?Global?test?environment?tear-down??
  19. [==========]?4?tests?from?1?test?case?ran.?(1?ms?total)??
  20. [??PASSED??]?3?tests.??
  21. [??FAILED??]?1?test,?listed?below:??
  22. [??FAILED??]?CHashTableTest.add2get??

?

[cpp]?view plaincopy
  1. </pre><p>可以看到,对于错误的CASE,会标出所在文件及其行数。</p><p></p>如果我们需要输出到XML文件,则执行./unittest?--gtest_output=xml,那么会在当前目录下生成test_detail.xml?文件,内容如下:<p></p><p></p><pre?name="code"?class="cpp"><?xml?version="1.0"?encoding="UTF-8"?>??
  2. <testsuites?tests="3"?failures="0"?disabled="0"?errors="0"?time="0.001"?name="AllTests">??
  3. ??<testsuite?name="CHashTableTest"?tests="3"?failures="0"?disabled="0"?errors="0"?time="0.001">??
  4. ????<testcase?name="hashfunc"?status="run"?time="0.001"?classname="CHashTableTest"?/>??
  5. ????<testcase?name="addget"?status="run"?time="0"?classname="CHashTableTest"?/>??
  6. ????<testcase?name="delget"?status="run"?time="0"?classname="CHashTableTest"?/>??
  7. ??</testsuite>??
  8. </testsuites>??

如此,一个简单的单元测试写完。因为太简单,所以不需要使用google mock模拟一些依赖。后续我再写结合google mock来写一些复杂的gtest单元测试。

下面来简单说下gtest的工作流程。


4、google test内部是如何执行我们的单元测试用例的

首先从main函数看起。

我们的main函数执行了RUN_ALL_TESTS宏,这个宏干了些什么事呢?

?

[cpp]?view plaincopy
  1. #define?RUN_ALL_TESTS()\??
  2. ??(::testing::UnitTest::GetInstance()->Run())??
  3. ??
  4. }??//?namespace?testing??

原来是调用了UnitTest静态工厂实例的Run方法!在gtest里,一切测试用例都是Test类的实例!所以,Run方法将会执行所有的Test实例来运行所有的单元测试,看看类图:

?


为什么说一切单元测试用例都是Test类的实例呢?

我们有两种写测试用例的方法,一种就是上面我说的TEST_F宏,这要求我们要显示的定义一个子类继承自Test类。在TEST_F宏里,会再次定义一个新类,继承自我们上面定义的子类(两重继承哈)。

第二种就是TEST宏,这个宏里不要求用户代码定义类,但在google test里,TEST宏还是定义了一个子类继承自Test类。

所以,UnitTest的Run方法只需要执行所有Test实例即可。


每个单元测试用例就是一个Test类子类的实例。它同时与TestResult,TestCase,TestInfo关联起来,用于提供结果。

当然,还有EventListen类来监控结果的输出,控制测试的进度等。


以上并没有深入细节,只是大致帮助大家理解,我们写的几个简单的gtest宏,和单元测试用例,到底是如何被执行的。接下来,我会通过gmock来深入的看看google单元测试的玩法。

    网友 2018/11/8 16:18:17 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

    网友 2018/11/8 16:17:38 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

    网友 2018/11/8 16:17:04 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

    网友 2018/11/8 16:16:24 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

    网友 2018/11/8 16:15:49 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

    网友 2018/11/8 16:15:15 发表

    深入浅出,大牛 但是你的代码咋好多乱码?

发表评论
用户名: 匿名