【簡(jiǎn)介】
gtest是一款由google開發(fā)并開源的C++單元測(cè)試框架,對(duì)C++的各種單元測(cè)試場(chǎng)景提供了完備的支持,并且可以在多種平臺(tái)下運(yùn)行,本文主要介紹gtest框架中測(cè)試部分的內(nèi)容(mock部分將在下一篇中介紹)。gtest在Github地址為:GitHub - google/googletest: Googletest - Google Testing and Mocking Framework??
下載并解壓后,gtest的目錄結(jié)構(gòu)如下圖所示:

gtest提供了兩種編譯方式bazel和cmake,本文時(shí)使用cmake進(jìn)行編譯:
mkdir build????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? cd build????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? cmake ../????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? make?????? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
編譯完成后會(huì)在文件夾build/lib中生成目標(biāo)庫(kù)文件:

在向工程中集成gtest框架時(shí)需要引入上述編譯好的庫(kù)和頭文件,其中l(wèi)ibgtest*.a是gtest相關(guān)的庫(kù),libgmock*.a系列是gmock相關(guān)的庫(kù)。它們對(duì)應(yīng)的頭文件位于代碼根目錄下googletest/include與googlemock/include文件夾。編寫測(cè)試代碼的時(shí)候,只需要包含頭文件 gtest.h或者gmock.h即可。
為了方便用戶使用,gtest框架中大量的測(cè)試代碼都是以宏調(diào)用的形式完成,在開始測(cè)試之前先介紹一個(gè)最基本的宏:
?????????????????????????????????????? TEST(testsuiteName,testcaseName)
TEST宏是gtest最基本的組成單元,在編寫測(cè)試代碼時(shí),會(huì)大量使用到該宏。TEST接收兩個(gè)參數(shù),第一個(gè)參數(shù)為testsuite(測(cè)試套件),第二個(gè)參數(shù)為testcase(測(cè)試用例)。概念上每一個(gè)testsuite代表了一組完成某個(gè)特定測(cè)試任務(wù)的testcase的集合,每一個(gè)testsuite可以由一個(gè)或者多個(gè)testcase組成。testcase代表了一個(gè)具體的測(cè)試動(dòng)作,在TEST宏內(nèi)部就是這個(gè)testcase具體測(cè)試的業(yè)務(wù)的代碼實(shí)現(xiàn):
TEST(AddFunctionTest,PositiveAdd)
{
?????????? ASSERT_EQ(add(1,2),3);
}
這個(gè)測(cè)試用例PositiveAdd屬于測(cè)試套件AddFunctionTest,內(nèi)部ASSERT_EQ*部分的意思是斷言函數(shù)add(1,2)執(zhí)行返回的結(jié)果與3相等。具體的測(cè)試用例編寫方式將在后文詳細(xì)描述。由于gtest的內(nèi)部實(shí)現(xiàn)中會(huì)對(duì)testsuite和testname的名字進(jìn)行改編,因此原則上在命名時(shí)不允許有下劃線出現(xiàn)(如果你加了下劃線也不會(huì)報(bào)錯(cuò),但是會(huì)有隱患)。
【斷言】
斷言是gtest核心組成,所有的測(cè)試用例最終都是以斷言實(shí)現(xiàn)的,因此gtest對(duì)斷言提供了豐富的宏支持。整體上gtest的斷言主要分為ASSERT*與EXPECT*系列,ASSERT*系列的斷言如果失敗,則會(huì)產(chǎn)生一個(gè)嚴(yán)重錯(cuò)誤并導(dǎo)致當(dāng)前作用范圍的測(cè)試用例中斷(請(qǐng)注意“當(dāng)前”,gtest中錯(cuò)誤是無(wú)法跨作用域傳遞的,如果需要傳遞則需要一些特殊的處理,這部分在后邊會(huì)介紹),相對(duì)的EXPECT*不會(huì)產(chǎn)生任何錯(cuò)誤,測(cè)試用例依舊可以繼續(xù)執(zhí)行。EXPECT*可以讓用戶在一個(gè)測(cè)試用例中檢查多次輸入返回,即使失敗也不退出;ASSERT*可以在測(cè)試用例中產(chǎn)生嚴(yán)重錯(cuò)誤導(dǎo)致后續(xù)操作無(wú)意義時(shí)直接中斷測(cè)試。這兩類斷言在語(yǔ)法支持上都是一一對(duì)應(yīng)的,可以根據(jù)具體的需求使用。

上圖中給出了兩個(gè)數(shù)比較的斷言說(shuō)明(摘自gtest說(shuō)明文檔primer.md),可以看到對(duì)于同一個(gè)斷言都有對(duì)應(yīng)的ASSERT與EXPECT版本,出了數(shù)字比較還有布爾類型、字符串等類型的比較斷言,具體的定義請(qǐng)讀者自行在gest.h中查找。
斷言擴(kuò)展:
除了通過(guò)之前介紹的ASSERT*與EXPECT*系列斷言支持各種類型的內(nèi)容檢查,gtest還提供了一些額外的擴(kuò)展斷言宏:
SUCCEED():產(chǎn)生一個(gè)成功標(biāo)識(shí),不會(huì)讓測(cè)試用例直接成功,只代表某一個(gè)步驟成功
FAIL():產(chǎn)生一個(gè)嚴(yán)重錯(cuò)誤,相當(dāng)于一個(gè)ASSERT*宏失敗
ASSERT_THROW(expre,type) :斷言表達(dá)式expre會(huì)拋出一個(gè)type類型的異常
ASSERT_ANY_THROW(expre):斷言表達(dá)式expre會(huì)拋出一個(gè)任意類型的異常
ASSERT_NO_THROW(expre): 斷言表達(dá)式expre不會(huì)拋出任何異常
【TESTFIXTURE】
在編寫單元測(cè)試用例的過(guò)程中,我們會(huì)遇到這樣的場(chǎng)景:一個(gè)測(cè)試套件由多個(gè)測(cè)試用例構(gòu)成,每個(gè)測(cè)試用例在執(zhí)行前需要編寫一些額外的代碼進(jìn)行數(shù)據(jù)初始化,而且在測(cè)試用例生成過(guò)程中,這部分?jǐn)?shù)據(jù)可能會(huì)發(fā)生改變,無(wú)法復(fù)用,從而產(chǎn)生了很多重復(fù)性的工作,因此gtest中引入了Testfixture。本質(zhì)上就是將上述資源管理動(dòng)作封裝到一個(gè)類中,在測(cè)試用例執(zhí)行前完成初始化,在執(zhí)行后進(jìn)行資源釋放。既然gtest提供的是單元測(cè)試框架,自然已經(jīng)提供了完備的支持,我們的接入方式也非常容易:
1.創(chuàng)建一個(gè)類公有繼承自::testing::Test。
2.類內(nèi)部已protected進(jìn)行聲明。
3.實(shí)現(xiàn)構(gòu)造/析構(gòu)或者SetUp/TearDown函數(shù)。
4.完善類的資源信息。
5.使用TEST_F宏替代TEST,第一個(gè)參數(shù)testsuite填寫新建類的名稱。
TEST_F宏聲明測(cè)試用例后,會(huì)在測(cè)試用例代碼執(zhí)行之前創(chuàng)建一個(gè)只屬于該測(cè)試用例的TestFixture類對(duì)象,在測(cè)試用例執(zhí)行結(jié)束后,會(huì)析構(gòu)該對(duì)象。步驟3中提到的兩對(duì)函數(shù):
???????????????????????????????????????
??????????????????????????????????????? 構(gòu)造/析構(gòu)函數(shù)
??????????????????????????????????????? SetUp/TearDown
它們都提供了資源的創(chuàng)建與釋放,它們的調(diào)用順序?yàn)椋簶?gòu)造 =》SetUp =》TearDown =》析構(gòu)。理論上只需要實(shí)現(xiàn)其中一對(duì)即可,但是由于C++語(yǔ)法限制與安全性考慮,這兩對(duì)函數(shù)有不同的應(yīng)用場(chǎng)景:
使用析構(gòu)/構(gòu)造函數(shù):
建議優(yōu)先使用構(gòu)造/析構(gòu)函數(shù)完成數(shù)據(jù)的初始化,這樣即使有別的類繼承自該TestFixture類,由于構(gòu)造/析構(gòu)鏈,可以保證所有的資源都被正確地釋放,同時(shí)在類的構(gòu)造函數(shù)中我們可以對(duì)類的成員進(jìn)行const修飾,這樣保證了數(shù)據(jù)的安全性。
使用SetUp/TearDown:
由于C++語(yǔ)法不允許在構(gòu)造/析構(gòu)函數(shù)中調(diào)用虛函數(shù);gtest的ASSERT*系列宏也無(wú)法在構(gòu)造/析構(gòu)函數(shù)中實(shí)現(xiàn);析構(gòu)函數(shù)中無(wú)法拋出異常,如果資源釋放過(guò)程可能有異常產(chǎn)生也只能放在TearDown中。
上述描述都是測(cè)試用例之間不可共享數(shù)據(jù)的例子,在這個(gè)基礎(chǔ)上如果產(chǎn)生了部分需要在測(cè)試用例之間共享的數(shù)據(jù)需求,按照C++語(yǔ)法的特性,只需要引入static類型的變量即可,對(duì)應(yīng)的::testing::Test中也實(shí)現(xiàn)了靜態(tài)函數(shù)對(duì)SetUpTestSuite/TearDownTestSuite。從名字就可以看出TestFixture本身也可以看做是一種特殊的測(cè)試套件。
整體上講SetUp/TearDown屬于測(cè)試用例內(nèi)部的資源共享,SetUpTestSuite/TearDownTestSuite屬于測(cè)試套件內(nèi)部的資源共享,全局的資源共享方式也是存在的,但是它已經(jīng)超越了TestFixture的范疇,因此不在本小節(jié)介紹。
【DeathTest】
程序中會(huì)有一些導(dǎo)致程序崩潰的異常分支,這也是單元測(cè)試需要覆蓋的部分之一,因此gtest提供了DEATHTEST系列宏提供程序崩潰的場(chǎng)景模擬,但是需要指出的是,下面介紹的DEATHTEST相關(guān)宏會(huì)創(chuàng)建一個(gè)單獨(dú)進(jìn)程來(lái)模擬程序崩潰的過(guò)程,并不是直接在當(dāng)前進(jìn)程完成的。常用的DEATHTEST宏如下:
ASSERT_DEATH(statement, matcher) :statement導(dǎo)致程序按照設(shè)定的錯(cuò)誤崩潰
ASSERT_EXIT(statement, predicate, matcher):statement導(dǎo)致程序按照設(shè)定的錯(cuò)誤退出,退出返回碼與predicate一致
其中參數(shù)matcher可以是一個(gè)用于匹配字符串的gmock matcher或者是一個(gè)正則表達(dá)式,他們通過(guò)匹配程序崩潰或者退出時(shí)stderr輸出的錯(cuò)誤信息,因此如果確實(shí)需要一個(gè)matcher,請(qǐng)確保matcher能正確匹配到期望的內(nèi)容,如果不需要匹配器直接填空字符串即可。
一個(gè)ASSERT_EXIT的例子:

ASSERT_DEATH比較簡(jiǎn)單,只需要構(gòu)建一個(gè)令程序崩潰的語(yǔ)句即可,在上述的ASSERT_EXIT例子中,通過(guò)SigRaise向程序發(fā)送了一個(gè)可以導(dǎo)致程序退出的信號(hào)SIGKILL(9),predicate參數(shù)為由testing提供的方法KilledBySignal,matcher直接置空,不進(jìn)行任何匹配。
如果對(duì)于上述例子進(jìn)行修改:


與之前的例子相比,這次試用了自定義的程序退出方法ExitNum,在程序退出的時(shí)候向stderr寫入了信息,在測(cè)試用例 ExitWith0中ASSERET_EXIT第三個(gè)參數(shù)填入了正則表達(dá)式,顯然無(wú)法完成匹配,因此執(zhí)行后會(huì)失敗,如果將正則表達(dá)式修改為"exit*",執(zhí)行就會(huì)發(fā)現(xiàn)測(cè)試通過(guò)。
需要注意的是DEATHTEST監(jiān)聽的是程序崩潰或者退出的狀態(tài),如果一個(gè)statement只是導(dǎo)致了程序拋出了一個(gè)異常,DEATHTEST的監(jiān)聽不會(huì)觸發(fā)。DEATHTEST有兩種模式fast與threadsafe,fast模式在子進(jìn)程中只執(zhí)行“死亡表達(dá)式”而threadsafe模式則會(huì)執(zhí)行完成的代碼,直到“死亡表達(dá)式”。顯示全局變量testing::FLAGS_gtest_death_test_style可以完成模式的切換(必須在測(cè)試用例執(zhí)行前調(diào)用)。
【完善測(cè)試錯(cuò)誤信息】
有些時(shí)候單元測(cè)試的目標(biāo)方法會(huì)比較復(fù)雜,中間會(huì)有很多分支,返回類型也不一定是布爾類型,按照之前介紹的ASSERT/EXPECT機(jī)制,如果只是簡(jiǎn)單的給出結(jié)果為TRUE或者FALSE,顯然不能準(zhǔn)確地反映出真實(shí)的測(cè)試情況。單元測(cè)試的目的是發(fā)現(xiàn)問(wèn)題并解決問(wèn)題,因此單元測(cè)試需要明確的告知用戶錯(cuò)誤產(chǎn)生的位置和原因。另外,有時(shí)候用戶需要測(cè)試一個(gè)復(fù)雜的表達(dá)式,而gtest提供的斷言往往是2元的,所以用戶為了進(jìn)行測(cè)試就需要編寫復(fù)雜的測(cè)試代碼,如果出錯(cuò)進(jìn)一步增加了獲取錯(cuò)誤原因的難度。既然gtest不能以窮舉的方法滿足用戶,只能提供了模板化的方式讓用戶完成自定義表達(dá)式與提示信息。
針對(duì)于不同的應(yīng)用場(chǎng)景gtest提供了不同的支持機(jī)制:
方法1:? Using an Existing Boolean Function
這種情況比較簡(jiǎn)單,因?yàn)楹瘮?shù)本身就只有TRUE與FALSE兩種值,因此我們只需有一個(gè)支持變參的斷言表達(dá)式即可。gtest提供了*_PRED*(pred,val1,...)系列斷言,表達(dá)式中第一個(gè)*代表 ASSERT或者EXPECT,第二個(gè)*是一個(gè)數(shù)字,代表了被測(cè)試表達(dá)式(函數(shù))的參數(shù)數(shù)量。下邊給出一個(gè)接收三個(gè)參數(shù)返回布爾類型的函數(shù)的測(cè)試:

方法2:Using a Function That Returns an AssertionResult
和方法1相比,這是一種普遍情況,我們可以用一種方式將各種返回值規(guī)整為可以使用gtest斷言處理的結(jié)果。gtest提供了一個(gè)類類型testing::AssertionResult,其中有兩個(gè)關(guān)鍵的方法:
????????????????????????????????????????? testing::AssertionSuccess()
????????????????????????????????????????? testing::AssertionFailure()
我們可以通過(guò)對(duì)函數(shù)的分支進(jìn)行分別處理進(jìn)而使其變成一個(gè)可"斷言"的表達(dá)式:

其中TriBoolFunc是一個(gè)接收兩個(gè)int類型的數(shù)字,如果相等返回0,a大于b返回大于0,a小于b返回小于0。在TriBoolFuncAssert中我們對(duì)返回結(jié)果進(jìn)行了改變,如果傳入的值a<b,我們則認(rèn)為產(chǎn)生了一個(gè)錯(cuò)誤(AssertionFailure),其他情況返回一個(gè)成功(AssertionSuccess)。
通過(guò)創(chuàng)建一個(gè)返回testing::AssertionResult的函數(shù)來(lái)封裝待測(cè)試函數(shù),相當(dāng)于是用另外一種方式使得所有的函數(shù)的各種返回類型(包括return返回、引用帶出返回值等),均可以轉(zhuǎn)化為一個(gè)可以使用斷言測(cè)試的結(jié)果。這是一種非常有效的方式,但是因?yàn)樵跀嘌詼y(cè)試時(shí)顯示調(diào)用的是另外一個(gè)方法,當(dāng)測(cè)試代碼達(dá)到一定規(guī)模時(shí),同樣的一個(gè)EXPECT_TRUE(func(a))我們無(wú)法直接從字面看出到底func是原始代碼還是經(jīng)過(guò)AssertionResult封裝的方法。因此gtest又引入了方法3的處理。
方法3:Using Predicate-Formatter
Predicate-Formatter就是用來(lái)解決方法2中的問(wèn)題,并給出了一個(gè)標(biāo)準(zhǔn)化的解決方案:
?????????????????????? ASSERT_PRED_FORMAT2(pred_format2, val1, val2)
?????????????????????? EXPECT_PRED_FORMAT2(pred_format2, val1, val2)
這個(gè)斷言格式與情況1中*_PRED*類似,F(xiàn)ORMAT后跟的數(shù)字代表了實(shí)際參數(shù)的數(shù)量。pred_format也是一個(gè)返回testing::AssertionResult的函數(shù),但是這個(gè)函數(shù)有一個(gè)標(biāo)準(zhǔn)的表達(dá)式:

其中exprn代表第n個(gè)參數(shù)的字符串表達(dá)式,Tn valn代表函數(shù)實(shí)際執(zhí)行業(yè)務(wù)需求的類型為Tn的參數(shù)。函數(shù)本身的實(shí)現(xiàn)方式與方法2中介紹的類似:

本質(zhì)上除了參數(shù)以外,其內(nèi)部實(shí)現(xiàn)與情況2中介紹的函數(shù)一致,唯一區(qū)別是使用斷言使用的是專用的斷言宏:

本質(zhì)上情況1中介紹的*_PRED*也屬于Predicate-Formatter,參考EXPECT_PRED1的實(shí)現(xiàn),在內(nèi)部只是自己實(shí)現(xiàn)了一個(gè)EXPECT_PRED_FORMAT要求的pred_format函數(shù):

總結(jié)一下方法1屬于方法3的進(jìn)一步封裝,由框架內(nèi)部實(shí)現(xiàn)了錯(cuò)誤信息的輸出。方法2給出了方法3的實(shí)現(xiàn)方式(此類問(wèn)題普遍的實(shí)現(xiàn)方式):本質(zhì)上都是將一個(gè)任意方法封裝成一個(gè)返回AssertionResult的函數(shù)。同時(shí)需要注意的是標(biāo)準(zhǔn)版本的gtest只提供了參數(shù)數(shù)量最多為5的宏,如果需要更多的參數(shù)需要自行實(shí)現(xiàn)或者聯(lián)系gtest官方。但是如果一個(gè)方法接收過(guò)多的參數(shù),首先應(yīng)該考慮對(duì)這個(gè)方法進(jìn)行重構(gòu)。
【訪問(wèn)類的私有成員】
原則上講在類外部訪問(wèn)一個(gè)類的私有成員這個(gè)需求是不合理的,既然將一個(gè)方法聲明為私有,則應(yīng)該通過(guò)類的共有成員對(duì)其進(jìn)行訪問(wèn)和驗(yàn)證。因此,如果遇到這樣的需求,首先應(yīng)該研究是否可以通過(guò)調(diào)整代碼的結(jié)構(gòu)來(lái)避免這種問(wèn)題。如果無(wú)法解決,只能通過(guò)宏FRIEND_TEST來(lái)“破壞”類的封閉性(本質(zhì)上是通過(guò)友元實(shí)現(xiàn)),但是不幸的是,這個(gè)宏需要寫入到源代碼中,導(dǎo)致測(cè)試代碼和源代碼糾纏在了一起。

如上圖代碼所示,類PrivateClass中調(diào)用了兩次FRIEND_TEST宏,在聲明后,測(cè)試套件PrivateClassSuite和PrivateClassFixture對(duì)應(yīng)的TESTCASE均可以訪問(wèn)類的私有方法add。如果目標(biāo)測(cè)試使用TEST宏,則可以直接調(diào)用,但是TESTSUITE與TESTCASE名稱必須與FRIEND_TEST中聲明一致。

如果要使用TEST_F宏則需要?jiǎng)?chuàng)建一個(gè)TESTFIXTURE,名字必須與FRIEND_TEST中聲明的一致。

需要注意的是創(chuàng)建TEST或者TEST_F時(shí)TESTSUITE與TESTCASE名字必須與之前在FRIEND_TEST中的聲明完全一致,否則會(huì)有編譯錯(cuò)誤。
【Value-Parameterized Tests】
當(dāng)我們?cè)诰帉憸y(cè)試用例的時(shí)候,需要向某個(gè)方法傳入不同的參數(shù)進(jìn)行驗(yàn)證,按照之前介紹的方法我們需要編寫大量的重復(fù)代碼。如果可以將傳入的值參數(shù)化,我們每次調(diào)用只需要修改傳入內(nèi)容即可。這就是gtest提供的Value-Parameterized技術(shù)。
首先需要?jiǎng)?chuàng)建一個(gè)TestFixture,除了繼承自testing::Test以外還需要繼承自:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??testing::WithParamInterface<T> ??
為了簡(jiǎn)化類定義,可以只繼承自類:
?????????????????????????????????? testing::TestWithParam<T>
其中T就是模板化的才參數(shù),需要在創(chuàng)建TextFixture時(shí)就指明,這就是可以多次傳入?yún)?shù)的類型。

需要注意的是,這個(gè)類仍然是一個(gè)TestFixture,雖然它隱式繼承了testing::Test,如果需要為其添加SetUp/TearDown,需要將其聲明為public而不是protected,否則其會(huì)因?yàn)樵L問(wèn)權(quán)限而無(wú)法正常工作。
然后引入一個(gè)新的宏TEST_P,與TEST和TEST_F不同的是,這個(gè)宏相當(dāng)于創(chuàng)建了一個(gè)測(cè)試模板,需要使用INSTANTIATE_TEST_SUITE_P宏完成參數(shù)的傳遞并創(chuàng)建真正的測(cè)試用例。

其中INSTANTIATE_TEST_SUITE_P第一個(gè)參數(shù)相當(dāng)于一個(gè)批量值測(cè)試的名字,可以自定義,第二個(gè)參數(shù)為之前定義的TestFixture名稱,第三個(gè)參數(shù)為傳遞的參數(shù)列表。在這個(gè)例子相當(dāng)于調(diào)用了三次EXPECT_EQ(keys,GetParam()),傳入的keys值為1,2,3。INSTANTIATE_TEST_SUITE_P宏只能聲明在全局或者命名空間范圍,不能將其放在某個(gè)方法內(nèi)部,否則無(wú)法編譯通過(guò)。
【Type Test】
當(dāng)一個(gè)函數(shù)有多個(gè)版本的實(shí)現(xiàn),接收不同類型的參數(shù),如果使用之前介紹的Value-Parameterized技術(shù),則需要根據(jù)每個(gè)實(shí)現(xiàn)版本創(chuàng)建一個(gè)TestFixture。為了減少重復(fù)代碼,我們可以把TestFixture模板化:

創(chuàng)建好模板類后,我們使用宏TYPED_TEST_SUITE將模板類實(shí)例化:

然后使用TYPED_TEST代替TEST_F完成測(cè)試用例的編寫:

這個(gè)例子中由于在實(shí)例化TestFixture時(shí),value_的類型會(huì)被設(shè)置為int和unsigned int,將其值設(shè)置為-1,unsigned int將會(huì)產(chǎn)生一個(gè)巨大的正整數(shù),這樣機(jī)會(huì)產(chǎn)生不同的測(cè)試結(jié)果。TYPED_TEST會(huì)按照TYPED_TEST_SUITE實(shí)例化的TestFixture類時(shí)傳入的類型,逐個(gè)構(gòu)建測(cè)試用例并執(zhí)行。
【Type-Parameterized Tests】
結(jié)合Type Test中的介紹,自然有方法可以類比Value-Parameterized實(shí)現(xiàn)Type-Parameterized技術(shù):

首先使用宏TYPED_TEST_SUITE_P創(chuàng)建一個(gè)Type-Parameterized的測(cè)試套件。
然后使用宏TYPED_TEST_P構(gòu)建一個(gè)測(cè)試用例模板,主要完成測(cè)試用例具體測(cè)試步驟。
然后使用用REGISTER_TYPED_TEST_SUITE_P完成注冊(cè),后續(xù)實(shí)例化時(shí)就會(huì)從已經(jīng)注冊(cè)的Type-Parameterized測(cè)試用例列表中逐個(gè)處理。
最后使用宏INSTANTIATE_TYPED_TEST_SUITE_P,傳入TestSuite名(參數(shù)2)和實(shí)例化類型(參數(shù)3)完成測(cè)試用例的實(shí)例化。
整體流程與Value-Parameterized類似,都是遵循創(chuàng)建TestFixture模板,創(chuàng)建測(cè)試用例模板,傳遞參數(shù)完成測(cè)試用例的實(shí)例化。核心思想都是用模板化技術(shù)來(lái)減少重復(fù)代碼的數(shù)量。
【全局共享資源】
之前在TestFixture中介紹了可以在Testcase與TestSuite級(jí)別共享資源的方式,gtest同樣提供了全局資源共享的模式,只不過(guò)使用方式稍有區(qū)別。這里需要?jiǎng)?chuàng)建一個(gè)環(huán)境類繼承自testing::Environment然后再其內(nèi)部實(shí)現(xiàn)SetUp/TearDown方法(構(gòu)造和析構(gòu)也是可以的),最后在測(cè)試main方法中進(jìn)行加載:

可以根據(jù)具體的需求在自定義的環(huán)境類中實(shí)現(xiàn)需要在全局共享的資源。在main方法需要進(jìn)行的處理:

testing::UnitTest是一個(gè)單例類,再其內(nèi)部會(huì)有一個(gè)vector存儲(chǔ)了所有Environment對(duì)象,在執(zhí)行RUN_ALL_TESTS時(shí)候會(huì)先執(zhí)行環(huán)境初始化,然后執(zhí)行測(cè)試用例,最后再清理環(huán)境。測(cè)試程序退出時(shí)會(huì)將所有的environment對(duì)象刪除。



【創(chuàng)建監(jiān)聽器】
gtest提供了測(cè)試中各種事件的回調(diào)方法,我們只需要向UnitTest對(duì)象實(shí)例注冊(cè)一個(gè)listener并實(shí)現(xiàn)listener中所關(guān)注的事件回調(diào)方法即可。實(shí)現(xiàn)方式與Environment類似:

testing::EmptyTestEventListener提供了豐富的事件監(jiān)聽回調(diào)方法,該類聲明位于gtest.h中,可以根據(jù)需求去查閱。
【單元測(cè)試的啟動(dòng)】
結(jié)合之前的例子知道,任意一個(gè)單元測(cè)試程序,必須按照順序執(zhí)行:
????????????????????????????????????? testing::InitGoogleTest(&argc,argv);
????????????????????????????????????? RUN_ALL_TESTS()
才能完成測(cè)試環(huán)境的初始化并執(zhí)行所有測(cè)試。當(dāng)單元測(cè)試用例達(dá)到一定規(guī)模,每個(gè)單獨(dú)的測(cè)試程序可能會(huì)有大量的測(cè)試用例,而在開發(fā)時(shí)我們可能會(huì)有各種各樣的執(zhí)行方式的需求:只執(zhí)行某一部分、屏蔽某一部分測(cè)試用例、循環(huán)執(zhí)行某一部分測(cè)試用例等。gtest提供了豐富的執(zhí)行參數(shù)支持,現(xiàn)在介紹一些常用的選項(xiàng):
--gtest_list_tests?? 不執(zhí)行test只是列出程序中包含的測(cè)試用例
--gtest_filter??? 根據(jù)過(guò)濾條件執(zhí)行某些測(cè)試用例
可以在TEST 或者TEST_F宏的testcase名字前加入關(guān)鍵字DISABLED_ 用來(lái)屏蔽某些測(cè)試用例,你也可以屏蔽一個(gè)TESTSUITE或者TESTFIXTURE,操作方式相當(dāng)于一個(gè)全局的替換,將X替換為DISABLED_X
--gtest_also_run_disabled_tests? 可以臨時(shí)運(yùn)行被DISABLE的測(cè)試用例,而不用修改代碼
--gtest_repeat=n?? 重復(fù)執(zhí)行測(cè)試代碼n次,n=-1會(huì)一直執(zhí)行
--gtest_shuffle???? 以隨機(jī)的順序執(zhí)行測(cè)試用例
執(zhí)行單元測(cè)試,默認(rèn)的結(jié)果是在命令窗口打印,有時(shí)候我們可能需要文件性質(zhì)的結(jié)果報(bào)告,gtest同樣也提供了生成xml和json格式的報(bào)告選項(xiàng):
選項(xiàng):--gtest_output??
--gtest_output=xml
--gtest_output=json
會(huì)按照xml或者json的格式將結(jié)果保存在本地,保存的名稱為 test_detail.json或者test_detail.xml;
如果需要將報(bào)告生成到指定目錄:
--gtest_output=xml:/usr/local
--gtest_output=json:/ussr/local
生成的文件名稱為 exe_TEST.json或者exe_TEST.xml,這里的exe代表執(zhí)行的測(cè)試程序的名稱;也可以在目錄后跟想要生成的名稱
--gtest_output=xml:/usr/local/a.xml
--gtest_output=json:/ussr/local/a.json
Thanks for reading ~