【轉】玩轉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 個無法解析的外部命令

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