玩轉Google開源C++單元測試架構Google Test系列__C++

來源:互聯網
上載者:User

http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html


前段時間學習和瞭解了下Google的開源C++單元測試架構Google Test,簡稱gtest,非常的不錯。 我們原來使用的是自己實現的一套單元測試架構,在使用過程中,發現越來越多使用不便之處,而這樣不便之處,gtest恰恰很好的解決了。

其實gtest本身的實現並不複雜,我們完全可以模仿gtest,不斷的完善我們的測試架構, 但最後我們還是決定使用gtest取代掉原來的自己的測試架構,原因是:

1.不斷完善我們的測試架構之後就會發覺相當於把gtest重新做了一遍,雖然輪子造的很爽,但是不是必要的。

2.使用gtest可以免去維護測試架構的麻煩,讓我們有更多精力投入到案例設計上。

3.gtest提高了非常完善的功能,並且簡單易用,極大的提高了編寫測試案例的效率。

gtest的官方網站是:

http://code.google.com/p/googletest/

從官方的使用文檔裡,你幾乎可以獲得你想要的所有東西

http://code.google.com/p/googletest/wiki/GoogleTestPrimer

http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide 

如果還想對gtest內部探個究竟,就把它的代碼下載下來研究吧,這就是開源的好處,哈。

官方已經有如此完備的文檔了,為什麼我還要寫呢。一方面是自己記記筆記,好記性不如爛筆頭,以後自己想查查一些用法也可以直接在這裡查到,一方面是對於不想去看一大堆英文文檔的朋友,在我這裡可以快速的找到gtest相關的內容。


額外篇:

1.gtest中如何跳出當前測試案例

2.編寫優美的GTest測試案例

3.gtest 參數化測試程式碼範例 (內含完整工程樣本)



玩轉Google開源C++單元測試架構Google Test系列(gtest)之一 - 初識gtest

一、前言

本篇將介紹一些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選項。

工程設定後了後,我們來編寫一個最簡單測試案例試試,我們先來寫一個被測試函數: 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. 提高了豐富的命令列參數對案例運行進行一系列的設定。


玩轉Google開源C++單元測試架構Google Test系列(gtest)之二 - 斷言 一、前言

這篇文章主要總結gtest中的所有斷言相關的宏。 gtest中,斷言的宏可以理解為分為兩類,一類是ASSERT系列,一類是EXPECT系列。一個直觀的解釋就是:

1. ASSERT_* 系列的斷言,當檢查點失敗時,退出當前函數(注意:並非退出當前案例)。

2. EXPECT_* 系列的斷言,當檢查點失敗時,繼續往下執行。 二、樣本

//  int型比較,預期值:3,實際值:Add(1, 2)
EXPECT_EQ( 3 , Add( 1 ,  2 ))
//  

 

假如你的Add(1, 2) 結果為4的話,會在結果中輸出: g:\myproject\c ++ \gtestdemo\gtestdemo\gtestdemo.cpp( 16 ): error: Value of: Add( 1 ,  2 )
  Actual: 4
Expected: 3

如果是將結果輸出到xml裡的話,將輸出:(關於將結果輸出為xml,見:http://www.cnblogs.com/coderzh/archive/2009/04/10/1432789.html)

< testcase  name ="Demo"  status ="run"  time ="0"  classname ="AddTest" >
       < failure  message ="Value of: Add(1, 2)  Actual: 4Expected: 3"  type ="" > <![CDATA[ g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp:16
Value of: Add(1, 2)
  Actual: 4
Expected: 3 ]]> </ failure >
</ testcase >

 

如果你對自動輸出的出錯資訊不滿意的話,你還可以通過操作符<<將一些自訂的資訊輸出,通常,這對於調試或是對一些檢查點的補充說明來說,非常有用。

下面舉個例子:

如果不使用<<操作符自訂輸出的話:
for  ( int  i  =   0 ; i  <  x.size();  ++ i)
{
    EXPECT_EQ(x[i], y[i]) ;
}


看到的結果將是這樣的,你根本不知道出錯時 i 等於幾:
g:\myproject\c ++ \gtestdemo\gtestdemo\gtestdemo.cpp( 25 ): error: Value of: y[i]
  Actual:  4
Expected: x[i]
Which  is :  3

 

如果使用<<操作符將一些重要訊息輸出的話:
for  ( int  i  =   0 ; i  <  x.size();  ++ i)
{
    EXPECT_EQ(x[i], y[i])  <<   " Vectors x and y differ at index  "   <<  i;
}


從輸出結果中就可以定位到在 i = 2 時出現了錯誤。這樣的輸出結果看起來更加有用,容易理解:  g:\myproject\c ++ \gtestdemo\gtestdemo\gtestdemo.cpp( 25 ): error: Value of: y[i]
  Actual:  4
Expected: x[i]
Which  is :  3
Vectors x and&nbnbsp;y differ at index  2

  三、布爾值檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false

  四、數值型資料檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_EQ(expected, actual); EXPECT_EQ(expected, actual); expected == actual
ASSERT_NE(val1, val2); EXPECT_NE(val1, val2); val1 != val2
ASSERT_LT(val1, val2); EXPECT_LT(val1, val2); val1 < val2
ASSERT_LE(val1, val2); EXPECT_LE(val1, val2); val1 <= val2
ASSERT_GT(val1, val2); EXPECT_GT(val1, val2); val1 > val2
ASSERT_GE(val1, val2); EXPECT_GE(val1, val2); val1 >= val2

  五、字串檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); the two C strings have the same content
ASSERT_STRNE(str1, str2); EXPECT_STRNE(str1, str2); the two C strings have different content
ASSERT_STRCASEEQ(expected_str, actual_str); EXPECT_STRCASEEQ(expected_str, actual_str); the two C strings have the same content, ignoring case
ASSERT_STRCASENE(str1, str2); EXPECT_STRCASENE(str1, str2); the two C strings have different content, ignoring case

 

*STREQ*和*STRNE*同時支援char*和wchar_t*類型的,*STRCASEEQ*和*STRCASENE*卻只接收char*,估計是不常用吧。下面是幾個例子: TEST(StringCmpTest, Demo)
{
     char *  pszCoderZh  =   " CoderZh " ;
    wchar_t *  wszCoderZh  =  L " CoderZh " ;
    std:: string  strCoderZh  =   " CoderZh " ;
    std::wstring wstrCoderZh  =  L " CoderZh " ;

    EXPECT_STREQ( " CoderZh " , pszCoderZh);
    EXPECT_STREQ(L " CoderZh " , wszCoderZh);

    EXPECT_STRNE( " CnBlogs " , pszCoderZh);
    EXPECT_STRNE(L " CnBlogs " , wszCoderZh);

    EXPECT_STRCASEEQ( " coderzh " , pszCoderZh);
     // EXPECT_STRCASEEQ(L"coderzh", wszCoderZh);    不支援

    EXPECT_STREQ( " CoderZh " , strCoderZh.c_str());
    EXPECT_STREQ(L " CoderZh " , wstrCoderZh.c_str());
}

  六、顯示返回成功或失敗

直接返回成功:SUCCEED();

返回失敗:

Fatal assertion Nonfatal assertion
FAIL(); ADD_FAILURE();

  TEST(ExplicitTest, Demo)
{
    ADD_FAILURE()  <<   " Sorry " ;  //  None Fatal Asserton,繼續往下執行。

     // FAIL();  //  Fatal Assertion,不往下執行該案例。

    SUCCEED();
}

七、異常檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_THROW(statement, exception_type); EXPECT_THROW(statement, exception_type); statement throws an exception of the given type
ASSERT_ANY_THROW(statement); EXPECT_ANY_THROW(statement); statement throws an exception of any type
ASSERT_NO_THROW(statement); EXPECT_NO_THROW(statement); statement doesn’t throw any exception

 

例如: 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);
}

TEST(FooTest, HandleZeroInput)
{
    EXPECT_ANY_THROW(Foo( 10 ,  0 ));
    EXPECT_THROW(Foo( 0 ,  5 ),  char * );
}

八、Predicate Assertions

在使用EXPECT_TRUE或ASSERT_TRUE時,有時希望能夠輸出更加詳細的資訊,比如檢查一個函數的傳回值TRUE還是FALSE時,希望能夠輸出傳入的參數是什麼,以便失敗後好跟蹤。因此提供了如下的斷言:

Fatal assertion Nonfatal assertion Verifies
ASSERT_PRED1(pred1, val1); EXPECT_PRED1(pred1, val1); pred1(val1) returns true
ASSERT_PRED2(pred2, val1, val2); EXPECT_PRED2(pred2, val1, val2); pred2(val1, val2) returns true

 

Google人說了,他們只提供<=5個參數的,如果需要測試更多的參數,直接告訴他們。下面看看這個東西怎麼用。
bool  MutuallyPrime( int  m,  int  n)
{
     return  Foo(m , n)  >   1 ;
}

TEST(PredicateAssertionTest, Demo)
{
     int  m  =   5 , n  =   6 ;
    EXPECT_PRED2(MutuallyPrime, m, n);
}

 

當失敗時,返回錯誤資訊:

error: MutuallyPrime(m, n) evaluates to false, where
m evaluates to 5
n evaluates to 6

如果對這樣的輸出不滿意的話,還可以自訂輸出格式,通過如下:

Fatal assertion Nonfatal assertion Verifies
ASSERT_PRED_FORMAT1(pred_format1, val1);` EXPECT_PRED_FORMAT1(pred_format1, val1); pred_format1(val1) is successful
ASSERT_PRED_FORMAT2(pred_format2, val1, val2); EXPECT_PRED_FORMAT2(pred_format2, val1, val2); pred_format2(val1, val2) is successful

 

用法樣本: t

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.