【转】玩转Google开源C++单元测试框架Google Test系列(gtest)之一 - 初识gtest

原文地址:http://www.cnblogs.com/coderzh/archive/2009/03/31/1426758.html

一、前言

本篇将介绍一些gtest的基本使用,包括下载,安装,编译,建立我们第一个测试Demo工程,以及编写一个最简单的测试案例。

二、下载

如果不记得网址, 直接在google里搜gtest,第一个就是。目前gtest的最新版本为1.3.0,从下列地址可以下载到该最新版本:

http://googletest.googlecode.com/files/gtest-1.3.0.zip  

http://googletest.googlecode.com/files/gtest-1.3.0.tar.gz  

http://googletest.googlecode.com/files/gtest-1.3.0.tar.bz2  

三、编译

下载解压后, 里面有个msvc目录:

  

使用VS的同学可以直接打开msvc里面的工程文件, 如果你在使用的是VS2005或是VS2008,打开后会提示你升级,升完级后,我们直接编译里面的“gtest”工程,可以直接编过的。

这里要提醒一下的是,如果你升级为VS2008的工程,那么你的测试Demo最好也是VS2008工程,不然你会发现很郁闷,你的Demo怎么也编不过,我也曾折腾了好久,当时我升级为了VS2008工程,结果我使用VS2005工程建Demo,死活编不过。(这里有人误解了,并不是说只能在VS2008中编译,在VS2005中同样可以。如果要编译VS2005版本,最好保证gtest和你的测试工程都使用VS2005工程。)

编译之后,在msvc里面的Debug或是Release目录里看到编译出来的gtestd.lib或是gtest.lib文件。

四、第一个Demo

下面我们开始建立我们的第一个Demo了,假如之前使用的VS2008编译的gtest,那么,我们在VS2008中,新建一个Win32 Console Application。接着就是设置工程属性,总结如下:

1.设置gtest头文件路径

2.设置gtest.lib路径

3.Runtime Library设置

 

如果是Release版本,Runtime Library设为/MT。当然,其实你也可以选择动态链接(/MD),前提是你之前编译的gtest也使用了同样是/MD选项。后面有测试,链接出错,这是选择连接crt库的方式,创建的gtest是静态库必须和工程项目使用相同的代码生成设置,同样gtest库使用MD,而工程使用MT也是类似的问题,觉得gtest生成dll应该不用链接crt库的方式进行严格限制,因为dll是内部例程被调用,并不是与工程程序执行实际的链接;


工程设置后了后,我们来编写一个最简单测试案例试试,我们先来写一个被测试函数:

int  Foo( int  a,  int  b)
{
    
 if  (a  ==   0   ||  b  ==   0 )
    {
        
 throw   " don't do that " ;
    }
    
 int  c  =  a  %  b;
    
 if  (c  ==   0 )
        
 return  b;
    
 return  Foo(b, c);
}

 

没错,上面的函数是用来求最大公约数的。下面我们就来编写一个简单的测试案例。

#include  < gtest / gtest.h > 

TEST(FooTest, HandleNoneZeroInput)
{
    EXPECT_EQ(
 2 , Foo( 4  10 ));
    EXPECT_EQ(
 6 , Foo( 30  18 ));
}

 

上面可以看到,编写一个测试案例是多么的简单。 我们使用了TEST这个宏,它有两个参数,官方的对这两个参数的解释为:[TestCaseName,TestName],而我对这两个参数的定义是: [TestSuiteName,TestCaseName],在下一篇我们再来看为什么这样定义。

对检查点的检查,我们上面使用到了EXPECT_EQ这个宏,这个宏用来比较两个数字是否相等。Google还包装了一系列EXPECT_* 和ASSERT_*的宏,而EXPECT系列和ASSERT系列的区别是:

    1. EXPECT_*  失败时,案例继续往下执行。

    2. ASSERT_* 失败时,直接在当前函数中返回,当前函数中ASSERT_*后面的语句将不会执行。

在下一篇,我们再来具体讨论这些断言宏。为了让我们的案例运行起来,我们还需要在main函数中添加如下代码:

int  _tmain( int  argc, _TCHAR *  argv[])
{
    testing::InitGoogleTest(
 & argc, argv);
    
 return  RUN_ALL_TESTS();
}

 

“testing::InitGoogleTest(&argc, argv);” :gtest的测试案例允许接收一系列的命令行参数,因此,我们将命令行参数传递给gtest,进行一些初始化操作。gtest的命令行参数非常丰富,在后面我们也会详细了解到。

“RUN_ALL_TESTS()” :运行所有测试案例

OK,一切就绪了,我们直接运行案例试试(一片绿色,非常爽):

五、总结

本篇内容确实是非常的初级,目的是让从来没有接触过gtest的同学了解gtest最基本的使用。gtest还有很多更高级的使用方法,我们将会在后面讨论。总结本篇的内容的话:

    1. 使用VS编译gtest.lib文件

    2. 设置测试工程的属性(头文件,lib文件,/MT参数(和编译gtest时使用一样的参数就行了))

    3. 使用TEST宏开始一个测试案例,使用EXPECT_*,ASSER_*系列设置检查点。

    4. 在Main函数中初始化环境,再使用RUN_ALL_TEST()宏运行测试案例。

优点:

    1. 我们的测试案例本身就是一个exe工程,编译之后可以直接运行,非常的方便。

    2. 编写测试案例变的非常简单(使用一些简单的宏如TEST),让我们将更多精力花在案例的设计和编写上。

    3. 提供了强大丰富的断言的宏,用于对各种不同检查点的检查。

    4. 提高了丰富的命令行参数对案例运行进行一系列的设置。





>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: __thiscall std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int)" (??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@H@Z) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> >::`vbase destructor'(void)" (??_D?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXXZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: char const * __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::c_str(void)const " (?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::length(void)const " (?length@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> >::str(void)const " (?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > & __thiscall std::basic_ostream<char,struct std::char_traits<char> >::operator<<(int)" (??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::locale::facet * __thiscall std::locale::facet::_Decref(void)" (?_Decref@facet@locale@std@@QAEPAV123@XZ) 已经在 gtestd.lib(gtest-all.obj) 中定义
1>libcpmtd.lib(ios.obj) : error LNK2005: "private: static void __cdecl std::ios_base::_Ios_base_dtor(class std::ios_base *)" (?_Ios_base_dtor@ios_base@std@@CAXPAV12@@Z) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(ios.obj) : error LNK2005: "public: static void __cdecl std::ios_base::_Addstd(class std::ios_base *)" (?_Addstd@ios_base@std@@SAXPAV12@@Z) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "void __cdecl _AtModuleExit(void (__cdecl*)(void))" (?_AtModuleExit@@YAXP6AXXZ@Z) 已经在 msvcprtd.lib(locale0_implib.obj) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: __Fac_tidy 已经在 msvcprtd.lib(locale0_implib.obj) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "private: static void __cdecl std::locale::facet::facet_Register(class std::locale::facet *)" (?facet_Register@facet@locale@std@@CAXPAV123@@Z) 已经在 msvcprtd.lib(locale0_implib.obj) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "private: static class std::locale::_Locimp * __cdecl std::locale::_Getgloballocale(void)" (?_Getgloballocale@locale@std@@CAPAV_Locimp@12@XZ) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "private: static class std::locale::_Locimp * __cdecl std::locale::_Init(void)" (?_Init@locale@std@@CAPAV_Locimp@12@XZ) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "public: static void __cdecl std::_Locinfo::_Locinfo_ctor(class std::_Locinfo *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?_Locinfo_ctor@_Locinfo@std@@SAXPAV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(locale0.obj) : error LNK2005: "public: static void __cdecl std::_Locinfo::_Locinfo_dtor(class std::_Locinfo *)" (?_Locinfo_dtor@_Locinfo@std@@SAXPAV12@@Z) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QAE@H@Z) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::~_Lockit(void)" (??1_Lockit@std@@QAE@XZ) 已经在 msvcprtd.lib(MSVCP90D.dll) 中定义
1>LIBCMTD.lib(setlocal.obj) : error LNK2005: __configthreadlocale 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(_file.obj) : error LNK2005: ___iob_func 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(osfinfo.obj) : error LNK2005: __open_osfhandle 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(dosmap.obj) : error LNK2005: __errno 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(dbgheap.obj) : error LNK2005: __CrtSetCheckCount 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __encode_pointer 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __decode_pointer 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(fflush.obj) : error LNK2005: _fflush 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(lconv.obj) : error LNK2005: _localeconv 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: _exit 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __exit 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __cexit 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __amsg_exit 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __initterm_e 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(mlock.obj) : error LNK2005: __lock 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(mlock.obj) : error LNK2005: __unlock 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(winxfltr.obj) : error LNK2005: __XcptFilter 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(stricmp.obj) : error LNK2005: __stricmp 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xi_a 已经在 MSVCRTD.lib(cinitexe.obj) 中定义
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xi_z 已经在 MSVCRTD.lib(cinitexe.obj) 中定义
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xc_a 已经在 MSVCRTD.lib(cinitexe.obj) 中定义
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xc_z 已经在 MSVCRTD.lib(cinitexe.obj) 中定义
1>LIBCMTD.lib(hooks.obj) : error LNK2005: "void __cdecl terminate(void)" (?terminate@@YAXXZ) 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(invarg.obj) : error LNK2005: __invalid_parameter 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(invarg.obj) : error LNK2005: __invoke_watson 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(sprintf.obj) : error LNK2005: _sprintf_s 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(getenv.obj) : error LNK2005: _getenv 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(strtol.obj) : error LNK2005: _strtol 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(strtoq.obj) : error LNK2005: __strtoui64 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(dbgrptw.obj) : error LNK2005: __CrtDbgReportW 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(vsnprnc.obj) : error LNK2005: __vsnprintf_s 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(printf.obj) : error LNK2005: _printf 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LIBCMTD.lib(vprintf.obj) : error LNK2005: _vprintf 已经在 MSVCRTD.lib(MSVCR90D.dll) 中定义
1>LINK : warning LNK4098: 默认库“MSVCRTD”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
1>LINK : warning LNK4098: 默认库“LIBCMTD”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
1>LIBCMTD.lib(crt0.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStartup 中被引用
1>E:\360data\重要数据\我的文档\Visual Studio 2008\Projects\gTest_Sample\Debug\gTest_Sample.exe : fatal error LNK1120: 1 个无法解析的外部命令

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章