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