青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
http://ray-leex.iteye.com/blog/212024

Google C++ Testing Framework Primer

 

翻譯:Ray Li (ray.leex@gmail.com
修改日期:2008年7月6日
原文參見:http://code.google.com/p/googletest/wiki/GoogleTestPrimer

 

Introduction:為什么需要Google C++ 測試框架?

 

Google C++ 測試框架幫助你更好地編寫C++測試。

 

無論你是在Linux,Windows,還是Mac環(huán)境下工作,只要你編寫C++代碼,Google 測試框架都可以幫上忙。

 

那么,哪些因素才能構(gòu)成一個好的測試?以及,Google C++ 測試框架怎樣滿足這些因素?我們相信:

  1. 測試應(yīng)該是獨立可重復(fù)的。因為其他測試成功或失敗而導(dǎo)致我們要對自己的測試進(jìn)行debug是非常痛苦的。Google C++ 測試框架通過將每個測試在不同的對象中運行,使得測試分離開來。當(dāng)一個測試失敗時,Google C++ 測試框架允許你獨立運行它以進(jìn)行快速除錯。
  2. 測試應(yīng)該能夠被很好地組織,并反映被測代碼的結(jié)構(gòu)。Google C++ 測試框架將測試組織成測試案例,案例中的測試可以共享數(shù)據(jù)和程序分支。這樣一種通用模式能夠很容易辨識,使得我們的測試容易維護(hù)。當(dāng)開發(fā)人員在項目之間轉(zhuǎn)換,開始在一個新的代碼基上開始工作時,這種一致性格外有用。
  3. 測試應(yīng)該是可移植可重用的。開源社區(qū)有很多平臺獨立的代碼,它們的測試也應(yīng)該是平臺獨立的。除開一些特殊情況,Google C++ 測試框架運行在不同的操作系統(tǒng)上、與不同的編譯器(gcc、icc、MSVC)搭配,Google C++ 測試框架的測試很容易與不同的配置一起工作。
  4. 當(dāng)測試失敗時,應(yīng)該提供盡可能多的、關(guān)于問題的信息。Google C++ 測試框架在第一個測試失敗時不會停下來。相反,它只是將當(dāng)前測試停止,然后繼續(xù)接下來的測試。你也可以設(shè)置對一些非致命的錯誤進(jìn)行報告,并接著進(jìn)行當(dāng)前的測試。這樣,你就可以在一次“運行-編輯-編譯”循環(huán)中檢查到并修復(fù)多個bug。
  5. 測試框架應(yīng)該能將測試編寫人員從一些環(huán)境維護(hù)的工作中解放出來,使他們能夠集中精力于測試的內(nèi)容。Google C++ 測試框架自動記錄下所有定義好的測試,不需要用戶通過列舉來指明哪些測試需要運行。
  6. 測試應(yīng)該快速。使用Google C++ 測試框架,你可以重用多個測試的共享資源,一次性完成設(shè)置/解除設(shè)置,而不用使一個測試去依賴另一測試。

因為Google C++ 測試框架基于著名的xUnit架構(gòu),如果你之前使用過JUnit或PyUnit的話,你將會感覺非常熟悉。如果你沒有接觸過這些測試框架,它也只會占用你大約10分鐘的時間來學(xué)習(xí)基本概念和上手。所以,讓我們開始吧!

 

Note:本文偶爾會用“Google Test”來代指“Google C++ 測試框架”。

 

基本概念

 

使用Google Test時,你是從編寫斷言開始的,而斷言是一些檢查條件是否為真的語句。一個斷言的結(jié)果可能是成功、非致命失敗,或者致命失敗。如果一個致命失敗出現(xiàn),他會結(jié)束當(dāng)前的函數(shù);否則,程序繼續(xù)正常運行。

 

測試使用斷言來驗證被測代碼的行為。如果一個測試崩潰或是出現(xiàn)一個失敗的斷言,那么,該測試失敗;否則該測試成功。

 

一個測試案例(test case)包含了一個或多個測試。你應(yīng)該將自己的測試分別歸類到測試案例中,以反映被測代碼的結(jié)構(gòu)。當(dāng)測試案例中的多個測試需要共享通用對象和子程序時,你可以把他們放到一個測試固件(test fixture)類中。

 

一個測試程序可以包含多個測試案例。

 

從編寫單個的斷言開始,到創(chuàng)建測試和測試案例,我們將會介紹怎樣編寫一個測試程序。

 

斷言

 

Google Test中的斷言是一些與函數(shù)調(diào)用相似的宏。要測試一個類或函數(shù),我們需要對其行為做出斷言。當(dāng)一個斷言失敗時,Google Test會在屏幕上輸出該代碼所在的源文件及其所在的位置行號,以及錯誤信息。也可以在編寫斷言時,提供一個自定義的錯誤信息,這個信息在失敗時會被附加在Google Test的錯誤信息之后。

 

斷言常常成對出現(xiàn),它們都測試同一個類或者函數(shù),但對當(dāng)前功能有著不同的效果。ASSERT_*版本的斷言失敗時會產(chǎn)生致命失敗,并結(jié)束當(dāng)前函數(shù)。EXPECT_*版本的斷言產(chǎn)生非致命失敗,而不會中止當(dāng)前函數(shù)。通常更推薦使用EXPECT_*斷言,因為它們運行一個測試中可以有不止一個的錯誤被報告出來。但如果在編寫斷言如果失敗,就沒有必要繼續(xù)往下執(zhí)行的測試時,你應(yīng)該使用ASSERT_*斷言。

 

因為失敗的ASSERT_*斷言會立刻從當(dāng)前的函數(shù)返回,可能會跳過其后的一些的清潔代碼,這樣也許會導(dǎo)致空間泄漏。根據(jù)泄漏本身的特質(zhì),這種情況也許值得修復(fù),也可能不值得我們關(guān)心——所以,如果你得到斷言錯誤的同時,還得到了一個堆檢查的錯誤,記住上面我們所說的這一點。

 

要提供一個自定義的錯誤消息,只需要使用<<操作符,或一個<<操作符的序列,將其輸入到框架定義的宏中。下面是一個例子:

 

 
Cpp代碼  收藏代碼
  1. ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";  
  2. for (int i = 0; i < x.size(); ++i) {  
  3.   EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;  
  4. }  
 

任何能夠被輸出到ostream中的信息都可以被輸出到一個斷言宏中——特別是C字符串和string對象。如果一個寬字符串(wchar_t*,windows上UNICODE模式TCHAR*或std::wstring)被輸出到一個斷言中,在打印時它會被轉(zhuǎn)換成UTF-8編碼。

 

基本斷言

 

下面這些斷言實現(xiàn)了基本的true/false條件測試。

 

致命斷言非致命斷言驗證條件
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition為真
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition 為假

 

記住,當(dāng)它們失敗時,ASSERT_*產(chǎn)生一個致命失敗并從當(dāng)前函數(shù)返回,而EXCEPT_*產(chǎn)生一個非致命失敗,允許函數(shù)繼續(xù)運行。在兩種情況下,一個斷言失敗都意味著它所包含的測試失敗。

 

有效平臺:Linux、Windows、Mac。

 

二進(jìn)制比較

 

本節(jié)描述了比較兩個值的一些斷言。

 

致命斷言非致命斷言驗證條件
ASSERT_EQ(expected,actual);EXPECT_EQ(expected,actual);expected == actual
ASSERT_NE(val1val2);EXPECT_NE(val1val2);val1 != val2
ASSERT_LT(val1val2);EXPECT_LT(val1val2);val1 < val2
ASSERT_LE(val1val2);EXPECT_LE(val1val2);val1 <= val2
ASSERT_GT(val1val2);EXPECT_GT(val1val2);val1 > val2
ASSERT_GE(val1val2);EXPECT_GE(val1val2);val1 >= val2

 

在出現(xiàn)失敗事件時,Google Test會將兩個值(Val1Val2)都打印出來。在ASSERT_EQ*和EXCEPT_EQ*斷言(以及我們隨后介紹類似的斷言)中,你應(yīng)該把你希望測試的表達(dá)式放在actual(實際值)的位置上,將其期望值放在expected(期望值)的位置上,因為Google Test的測試消息為這種慣例做了一些優(yōu)化。

 

參數(shù)值必須是可通過斷言的比較操作符進(jìn)行比較的,否則你會得到一個編譯錯誤。參數(shù)值還必須支持<<操作符來將值輸入到ostream中。所有的C++內(nèi)置類型都支持這一點。

 

這些斷言可以用于用戶自定義的型別,但你必須重載相應(yīng)的比較操作符(如==、<等)。如果定義有相應(yīng)的操作符,推薦使用ASSERT_*()宏,因為它們不僅會輸出比較的結(jié)果,還會輸出兩個比較對象。

 

參數(shù)表達(dá)式總是只被解析一次。因此,參數(shù)表達(dá)式有一定的副作用(side effect,這里應(yīng)該是指編譯器不同,操作符解析順序的不確定性)也是可以接受的。但是,同其他普通C/C++函數(shù)一樣,參數(shù)表達(dá)式的解析順序是不確定的(如,一種編譯器可以自由選擇一種順序來進(jìn)行解析),而你的代碼不應(yīng)該依賴于某種特定的參數(shù)解析順序。

 

ASSERT_EQ()對指針進(jìn)行的是指針比較。即,如果被用在兩個C字符串上,它會比較它們是否指向同樣的內(nèi)存地址,而不是它們所指向的字符串是否有相同值。所以,如果你想對兩個C字符串(例如,const char*)進(jìn)行值比較,請使用ASSERT_STREQ()宏,該宏會在后面介紹到。特別需要一提的是,要驗證一個C字符串是否為空(NULL),使用ASSERT_STREQ(NULL, c_string)。但是要比較兩個string對象時,你應(yīng)該使用ASSERT_EQ。

 

本節(jié)中介紹的宏都可以處理窄字符串對象和寬字符串對象(string和wstring)。

 

有效平臺:Linux、Windows、Mac。

 

字符串比較

 

該組斷言用于比較兩個C字符串。如果你想要比較兩個string對象,相應(yīng)地使用EXPECT_EQ、EXPECT_NE等斷言。

 

致命斷言非致命斷言驗證條件
ASSERT_STREQ(expected_str,actual_str);EXPECT_STREQ(expected_str,actual_str);兩個C字符串有相同的內(nèi)容
ASSERT_STRNE(str1str2);EXPECT_STRNE(str1str2);兩個C字符串有不同的內(nèi)容
ASSERT_STRCASEEQ(expected_str,actual_str);EXPECT_STRCASEEQ(expected_str,actual_str);兩個C字符串有相同的內(nèi)容,忽略大小寫
ASSERT_STRCASENE(str1str2);EXPECT_STRCASENE(str1str2);兩個C字符串有不同的內(nèi)容,忽略大小寫

 

注意斷言名稱中出現(xiàn)的“CASE”意味著大小寫被忽略了。

 

*STREQ*和*STRNE*也接受寬字符串(wchar_t*)。如果兩個寬字符串比較失敗,它們的值會做為UTF-8窄字符串被輸出。

 

一個NULL空指針和一個空字符串會被認(rèn)為是不一樣的。

 

有效平臺:Linux、Windows、Mac。

 

參見:更多的字符串比較的技巧(如子字符串、前綴和正則表達(dá)式匹配),請參見[Advanced Guide Advanced Google Test Guide]。

 

簡單的測試

 

要創(chuàng)建一個測試:

  1. 使用TEST()宏來定義和命名一個測試函數(shù),它們是一些沒有返回值的普通C++函數(shù)。
  2. 在這個函數(shù)中,與你想要包含的其它任何有效C++代碼一起,使用Google Test提供的各種斷言來進(jìn)行檢查。
  3. 測試的結(jié)果由其中的斷言決定;如果測試中的任意斷言失?。o論是致命還是非致命),或者測試崩潰,那么整個測試就失敗了。否則,測試通過。 
Cpp代碼  收藏代碼
  1. TEST(test_case_name, test_name) {  
  2. ... test body ...  
  3. }  
 

TEST()的參數(shù)是從概括到特殊的。第一個參數(shù)是測試案例的名稱,第二個參數(shù)是測試案例中的測試的名稱。記住,一個測試案例可以包含任意數(shù)量的獨立測試。一個測試的全稱包括了包含它的測試案例名稱,及其獨立的名稱。不同測試案例中的獨立測試可以有相同的名稱。

 

舉例來說,讓我們看一個簡單的整數(shù)函數(shù):

 

Cpp代碼  收藏代碼
  1. int Factorial(int n); // 返回n的階乘  
 

 

這個函數(shù)的測試案例應(yīng)該看起來像是:

 

Cpp代碼  收藏代碼
  1. // 測試0的階乘  
  2. TEST(FactorialTest, HandlesZeroInput) {  
  3.   EXPECT_EQ(1, Factorial(0));  
  4. }  
  5. // 測試正數(shù)的階乘  
  6. TEST(FactorialTest, HandlesPositiveInput) {  
  7.   EXPECT_EQ(1, Factorial(1));  
  8.   EXPECT_EQ(2, Factorial(2));  
  9.   EXPECT_EQ(6, Factorial(3));  
  10.   EXPECT_EQ(40320, Factorial(8));  
  11. }  
 

 

Google Test根據(jù)測試案例來分組收集測試結(jié)果,因此,邏輯相關(guān)的測試應(yīng)該在同一測試案例中;換句話說,它們的TEST()的第一個參數(shù)應(yīng)該是一樣的。在上面的例子中,我們有兩個測試,HandlesZeroInput和HandlesPostiveInput,它們都屬于同一個測試案例FactorialTest。

 

有效平臺:Linux、Windows、Mac。

 

測試固件(Test Fixtures,又做測試夾具、測試套件):在多個測試中使用同樣的數(shù)據(jù)配置

 

當(dāng)你發(fā)現(xiàn)自己編寫了兩個或多個測試來操作同樣的數(shù)據(jù),你可以采用一個測試固件。它讓你可以在多個不同的測試中重用同樣的對象配置。

 

要創(chuàng)建測試固件,只需:

  1. 創(chuàng)建一個類繼承自testing::Test。將其中的成員聲明為protected:或是public:,因為我們想要從子類中存取固件成員。
  2. 在該類中聲明你計劃使用的任何對象。
  3. 如果需要,編寫一個默認(rèn)構(gòu)造函數(shù)或者SetUp()函數(shù)來為每個測試準(zhǔn)備對象。常見錯誤包括將SetUp()拼寫為Setup()(小寫了u)——不要讓它發(fā)生在你身上。
  4. 如果需要,編寫一個析構(gòu)函數(shù)或者TearDown()函數(shù)來釋放你在SetUp()函數(shù)中申請的資源。要知道什么時候應(yīng)該使用構(gòu)造函數(shù)/析構(gòu)函數(shù),什么時候又應(yīng)該使用SetUp()/TearDown()函數(shù),閱讀我們的FAQ。
  5. 如果需要,定義你的測試所需要共享的子程序。

當(dāng)我們要使用固件時,使用TEST_F()替換掉TEST(),它允許我們存取測試固件中的對象和子程序:

 

Cpp代碼  收藏代碼
  1. TEST_F(test_case_name, test_name) {  
  2. ... test body ...  
  3. }  

 

與TEST()一樣,第一個參數(shù)是測試案例的名稱,但對TEST_F()來說,這個名稱必須與測試固件類的名稱一些。你可能已經(jīng)猜到了:_F正是指固件。

 

不幸地是,C++宏系統(tǒng)并不允許我們創(chuàng)建一個單獨的宏來處理兩種類型的測試。使用錯誤的宏會導(dǎo)致編譯期的錯誤。

 

而且,你必須在TEST_F()中使用它之前,定義好這個測試固件類。否則,你會得到編譯器的報錯:“virtual outside class declaration”。

對于TEST_F()中定義的每個測試,Google Test將會:

  1. 在運行時創(chuàng)建一個全新的測試固件
  2. 馬上通過SetUp()初始化它,
  3. 運行測試
  4. 調(diào)用TearDown()來進(jìn)行清理工作
  5. 刪除測試固件。注意,同一測試案例中,不同的測試擁有不同的測試固件。Google Test在創(chuàng)建下一個測試固件前總是會對現(xiàn)有固件進(jìn)行刪除。Google Test不會對多個測試重用一個測試固件。測試對測試固件的改動并不會影響到其他測試。

例如,讓我們?yōu)橐粋€名為Queue的FIFO隊列類編寫測試,該類的接口如下:

 
Cpp代碼  收藏代碼
  1. template <typename E> // E為元素類型  
  2. class Queue {  
  3. public:  
  4.   Queue();  
  5.   void Enqueue(const E& element);  
  6.   E* Dequeue(); // 返回 NULL 如果隊列為空.  
  7.   size_t size() const;  
  8.   ...  
  9. };  

 

首先,定義一個固件類。習(xí)慣上,你應(yīng)該把它的名字定義為FooTest,這里的Foo是被測試的類。

 
Cpp代碼  收藏代碼
  1. class QueueTest : public testing::Test {  
  2. protected:  
  3.   virtual void SetUp() {  
  4.     q1_.Enqueue(1);  
  5.     q2_.Enqueue(2);  
  6.     q2_.Enqueue(3);  
  7.   }  
  8.   // virtual void TearDown() {}  
  9.   Queue<int> q0_;  
  10.   Queue<int> q1_;  
  11.   Queue<int> q2_;  
  12. };  
 

在這個案例中,我們不需要TearDown(),因為每個測試后除了析構(gòu)函數(shù)外不需要進(jìn)行其它的清理工作了。

 

接下來我們使用TEST_F()和這個固件來編寫測試。

 

Cpp代碼  收藏代碼
  1. TEST_F(QueueTest, IsEmptyInitially) {  
  2.   EXPECT_EQ(0, q0_.size());  
  3. }  
  4. TEST_F(QueueTest, DequeueWorks) {  
  5.   int* n = q0_.Dequeue();  
  6.   EXPECT_EQ(NULL, n);  
  7.   
  8.   n = q1_.Dequeue();  
  9.   ASSERT_TRUE(n != NULL);  
  10.   EXPECT_EQ(1, *n);  
  11.   EXPECT_EQ(0, q1_.size());  
  12.   delete n;  
  13.   
  14.   n = q2_.Dequeue();  
  15.   ASSERT_TRUE(n != NULL);  
  16.   EXPECT_EQ(2, *n);  
  17.   EXPECT_EQ(1, q2_.size());  
  18.   delete n;  
  19. }  
 

上面這段代碼既使用了ASSERT_*斷言,又使用了EXPECT_*斷言。經(jīng)驗上講,如果你想要斷言失敗后,測試能夠繼續(xù)進(jìn)行以顯示更多的錯誤時,你應(yīng)該使用EXPECT_*斷言;使用ASSERT_*如果該斷言失敗后繼續(xù)往下執(zhí)行毫無意義。例如,Dequeue測試中的第二個斷言是ASSERT_TURE(n!= NULL),因為我們隨后會n指針解引用,如果n指針為空的話,會導(dǎo)致一個段錯誤。

 

當(dāng)這些測試開始時,會發(fā)生如下情況:

  1. Google Test創(chuàng)建一個QueueTest對象(我們把它叫做t1)。
  2. t1.SetUp()初始化t1。
  3. 第一個測試(IsEmptyInitiallly)在t1上運行。
  4. 測試完成后,t1.TearDown()進(jìn)行一些清理工作。
  5. t1被析構(gòu)。
  6. 以上步驟在另一個QueueTest對象上重復(fù)進(jìn)行,這回會運行DequeueWorks測試。

有效平臺:Linux、Windows、Mac。

 

注意:當(dāng)一個測試對象被構(gòu)造時,Google Test會自動地保存所有的Google Test變量標(biāo)識,對象析構(gòu)后進(jìn)行恢復(fù)。

 

調(diào)用測試

 

TEST()和TEST_F()向Google Test隱式注冊它們的測試。因此,與很多其他的C++測試框架不同,你不需要為了運行你定義的測試而將它們?nèi)吭倭谐鰜硪淮巍?/p>

 

在定義好測試后,你可以通過RUN_ALL_TESTS()來運行它們,如果所有測試成功,該函數(shù)返回0,否則會返回1.注意RUN_ALL_TESTS()會運行你鏈接到的所有測試——它們可以來自不同的測試案例,甚至是來自不同的文件。

 

當(dāng)被調(diào)用時,RUN_ALL_TESTS()宏會:

  1. 保存所有的Google Test標(biāo)志。
  2. 為一個側(cè)測試創(chuàng)建測試固件對象。
  3. 調(diào)用SetUp()初始化它。
  4. 在固件對象上運行測試。
  5. 調(diào)用TearDown()清理固件。
  6. 刪除固件。
  7. 恢復(fù)所有Google Test標(biāo)志的狀態(tài)。
  8. 重復(fù)上訴步驟,直到所有測試完成。

此外,如果第二步時,測試固件的構(gòu)造函數(shù)產(chǎn)生一個致命錯誤,繼續(xù)執(zhí)行3至5部顯然沒有必要,所以它們會被跳過。與之相似,如果第3部產(chǎn)生致命錯誤,第4部也會被跳過。

 

重要:你不能忽略掉RUN_ALL_TESTS()的返回值,否則gcc會報一個編譯錯誤。這樣設(shè)計的理由是自動化測試服務(wù)會根據(jù)測試退出返回碼來決定一個測試是否通過,而不是根據(jù)其stdout/stderr輸出;因此你的main()函數(shù)必須返回RUN_ALL_TESTS()的值。

 

而且,你應(yīng)該只調(diào)用RUN_ALL_TESTS()一次。多次調(diào)用該函數(shù)會與Google Test的一些高階特性(如線程安全死亡測試thread-safe death tests)沖突,因而是不被支持的。

 

有效平臺:Linux、Windows、Mac。

 

編寫main()函數(shù)

 

你可以從下面這個樣板開始:

 

Cpp代碼  收藏代碼
  1. #include "this/package/foo.h"  
  2. #include <gtest/gtest.h>  
  3. namespace {  
  4. // 測試Foo類的測試固件  
  5. class FooTest : public testing::Test {  
  6. protected:  
  7.   // You can remove any or all of the following functions if its body  
  8.   // is empty.  
  9.   FooTest() {  
  10.     // You can do set-up work for each test here.  
  11.   }  
  12.   virtual ~FooTest() {  
  13.     // You can do clean-up work that doesn't throw exceptions here.  
  14.   }  
  15.   // If the constructor and destructor are not enough for setting up  
  16.   // and cleaning up each test, you can define the following methods:  
  17.   virtual void SetUp() {  
  18.     // Code here will be called immediately after the constructor (right  
  19.     // before each test).  
  20.   }  
  21.   virtual void TearDown() {  
  22.     // Code here will be called immediately after each test (right  
  23.     // before the destructor).  
  24.   }  
  25.   // Objects declared here can be used by all tests in the test case for Foo.  
  26. };  
  27.   
  28. // Tests that the Foo::Bar() method does Abc.  
  29. TEST_F(FooTest, MethodBarDoesAbc) {  
  30.   const string input_filepath = "this/package/testdata/myinputfile.dat";  
  31.   const string output_filepath = "this/package/testdata/myoutputfile.dat";  
  32.   Foo f;  
  33.   EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));  
  34. }  
  35.   
  36. // Tests that Foo does Xyz.  
  37. TEST_F(FooTest, DoesXyz) {  
  38.   // Exercises the Xyz feature of Foo.  
  39. }  
  40. }  // namespace  
  41.   
  42. int main(int argc, char **argv) {  
  43.   testing::InitGoogleTest(&argc, argv);  
  44.   return RUN_ALL_TESTS();  
  45. }  

 

testing::InitGoogleTest()函數(shù)負(fù)責(zé)解析命令行傳入的Google Test標(biāo)志,并刪除所有它可以處理的標(biāo)志。這使得用戶可以通過各種不同的標(biāo)志控制一個測試程序的行為。關(guān)于這一點我們會在GTestAdvanced中講到。你必須在調(diào)用RUN_ALL_TESTS()之前調(diào)用該函數(shù),否則就無法正確地初始化標(biāo)示。

 

在Windows上InitGoogleTest()可以支持寬字符串,所以它也可以被用在以UNICODE模式編譯的程序中。

 

進(jìn)階閱讀

 

恭喜你!你已經(jīng)學(xué)到了一些Google Test基礎(chǔ)。你可以從編寫和運行幾個Google Test測試開始,再閱讀一下GoogleTestSamples,或是繼續(xù)研究GoogleTestAdvancedGuide,其中描述了很多更有用的Google Test特性。

 

已知局限

 

Google Test被設(shè)計為線程安全的。但是,我們還沒有時間在各種平臺上實現(xiàn)同步原語(synchronization primitives)。因此,目前從兩個線程同時使用Google Test斷言是不安全的。由于通常斷言是在主線程中完成的,因此在大多數(shù)測試中這都不算問題。如果你愿意幫忙,你可以試著在gtest-port.h中實現(xiàn)必要的同步原語。


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品久久午夜夜伦鲁鲁| 国产在线高清精品| 欧美日韩精品欧美日韩精品| 欧美韩日高清| 欧美日韩亚洲高清| 欧美午夜片在线观看| 国产精品拍天天在线| 国产热re99久久6国产精品| 国产一区二区三区奇米久涩 | 小处雏高清一区二区三区| 亚洲影音一区| 欧美影院在线| 久久午夜精品| 欧美精品国产精品日韩精品| 欧美性色aⅴ视频一区日韩精品| 国产精品成av人在线视午夜片| 国产精品一区亚洲| 影音国产精品| 这里只有精品丝袜| 久久精品成人一区二区三区| 免费看亚洲片| 亚洲精品综合久久中文字幕| 亚洲欧美国内爽妇网| 久久一区中文字幕| 欧美色一级片| 狠狠色香婷婷久久亚洲精品| 亚洲精品日韩综合观看成人91| 亚洲午夜免费福利视频| 久久精品人人爽| 亚洲国产成人久久综合一区| 99在线精品观看| 久久都是精品| 欧美日韩免费看| 国产在线精品二区| 日韩一级裸体免费视频| 欧美一区二区视频网站| 欧美激情视频在线播放| 亚洲一区二区动漫| 免费在线亚洲欧美| 国产美女精品人人做人人爽| 亚洲日本成人| 久久成人免费视频| 亚洲精品国精品久久99热| 香蕉乱码成人久久天堂爱免费| 欧美成人按摩| 国产视频精品xxxx| 一区二区激情视频| 毛片一区二区| 亚洲影院在线观看| 欧美成在线观看| 国产亚洲精久久久久久| 亚洲视频在线观看网站| 欧美大色视频| 亚洲欧美日韩人成在线播放| 欧美激情中文字幕一区二区| 国产在线精品一区二区夜色| 亚洲影视综合| 亚洲国产第一| 久久亚洲私人国产精品va| 国产精品捆绑调教| 日韩一区二区高清| 暖暖成人免费视频| 欧美一区在线直播| 国产精品国产三级国产专播品爱网 | 狂野欧美性猛交xxxx巴西| 一区二区日韩| 欧美国产日韩一区二区| 一区在线视频| 久久爱91午夜羞羞| 在线视频精品一区| 欧美日韩和欧美的一区二区| 精品999久久久| 久久激情婷婷| 午夜精品久久久| 国产精品美女黄网| 亚洲主播在线| 日韩午夜在线播放| 欧美精品亚洲| 亚洲九九爱视频| 欧美激情综合色| 久久综合导航| 亚洲国产精品成人综合色在线婷婷| 久久久精品一区| 欧美在线不卡| 国内久久精品| 久久久久国产精品麻豆ai换脸| 亚洲欧美在线高清| 国产精品一区在线观看你懂的| 亚洲欧美bt| 一本色道久久| 国产精品久线观看视频| 亚洲女性裸体视频| 亚洲一区二区三区乱码aⅴ| 欧美午夜精品一区| 亚洲欧美久久久| 亚洲综合色网站| 国产欧美一区二区三区久久人妖 | 乱码第一页成人| 亚洲精品1234| 亚洲国产毛片完整版| 欧美激情女人20p| 日韩视频一区二区三区| 亚洲另类视频| 国产精品国产精品| 久久精精品视频| 久久精品国产精品亚洲综合| 伊人婷婷欧美激情| 欧美大片一区| 欧美日韩精品不卡| 亚洲综合视频一区| 亚洲欧洲99久久| 激情成人中文字幕| 亚洲国产91| 欧美视频国产精品| 欧美伊人久久| 久久夜色精品国产欧美乱极品| 亚洲欧洲一区二区天堂久久| 亚洲精品无人区| 国产精品久久二区| 久久久久高清| 免费视频一区二区三区在线观看| 亚洲看片免费| 亚洲视频999| 韩日成人在线| 亚洲国产91色在线| 国产精品豆花视频| 久久免费精品日本久久中文字幕| 毛片av中文字幕一区二区| 一区二区av在线| 亚洲欧美视频一区| 亚洲电影观看| 正在播放欧美一区| 黄色精品网站| 亚洲美女色禁图| 国产一区在线免费观看| 欧美激情一区二区三区四区| 欧美午夜www高清视频| 久久一区亚洲| 欧美日韩国产黄| 久久精品免视看| 欧美精品久久久久久久久老牛影院| 亚洲欧美日本日韩| 久久一区二区精品| 午夜精品福利一区二区三区av| 久久久久se| 亚洲专区在线| 免费一区视频| 久久精品中文字幕一区| 欧美精品一卡| 另类国产ts人妖高潮视频| 欧美日一区二区在线观看| 另类专区欧美制服同性| 国产精品国产三级国产a| 欧美国产精品久久| 国产色婷婷国产综合在线理论片a| 亚洲电影下载| 国产专区综合网| 在线一区二区日韩| 亚洲精品日韩欧美| 久久aⅴ国产紧身牛仔裤| 亚洲一区二区三区精品视频| 免费91麻豆精品国产自产在线观看| 午夜激情久久久| 欧美另类一区二区三区| 另类激情亚洲| 国产视频精品xxxx| 在线视频精品一区| 99视频超级精品| 久久亚洲风情| 久久青草欧美一区二区三区| 国产精品国产三级国产a| 亚洲黄色三级| 亚洲国产精品传媒在线观看| 久久不射中文字幕| 欧美一区二区三区在线观看 | 亚洲午夜免费福利视频| 欧美激情精品久久久久久蜜臀| 开心色5月久久精品| 国产一区二区看久久| 亚洲在线观看| 亚洲一区二区不卡免费| 欧美激情第三页| 亚洲国产综合91精品麻豆| 禁久久精品乱码| 欧美制服丝袜第一页| 久久国产精品72免费观看| 国产精品一区久久久| 亚洲视频碰碰| 亚洲一区尤物| 欧美婷婷久久| 日韩网站在线看片你懂的| 亚洲最新在线视频| 欧美精品系列| 亚洲乱码国产乱码精品精可以看 | 91久久国产自产拍夜夜嗨| 亚洲激情视频在线观看| 免费成人在线观看视频| 亚洲福利免费| 亚洲美女91| 欧美日韩综合在线|