借用上面Add函數寫個固件測試的例子:
編譯運行效果如下:
必須強調,每個TEST_F開始都創建了一個新的帶固件對象,因此每個測試都使用獨立的完全相同的初始環境,各測試可以按任意順序執行(參見--gtest_shuffle命令行選項)。但在某些情況下,我們可能需要在各個測試間共享一個相同的環境來保存和傳遞狀態,或者環境的狀態是只讀的,可以只初始化一次,再或者創建環境的過程開銷很高,要求只初始化一次。共享某個固件環境的所有測試合稱為一個“測試套件”(TestSuite),gtest中利用靜態成員變量和靜態成員函數實現這個概念:
1、(可選)在testing::Test的派生類中,定義若干靜態成員變量來維護套件的狀態。
2、(可選)建立共享環境:定義一個靜態成員函數staticvoidSetUpTestCase()。
3、(可選)銷毀共享環境:定義一個靜態成員函數staticvoidTearDownCase()。
另外,還可以使用gtest的Environment類來建立和銷毀所有測試共用的全局環境(對應于上圖顯示的“Globaltestenvironmentset-up”和“Globaltestenvironmenttear-down”):
gtest文檔建議測試程序自己定義main函數并在其中創建和注冊全局環境對象:
三、異常測試
C程序中要返回出錯信息,可以利用特定的函數返回值、函數的輸出(outbound)參數、或者設置全局變量(如C標準庫定義的errno,Windows API中的“上次錯誤”(last error)代碼,Winsock中與每個socket相關聯的錯誤代碼)。C++程序常用異常(exception)來返回出錯信息,gtest為異常測試提供了專用的測試宏:
需要注意,這些測試宏都接受C/C++語句作為參數,所以既可以像前面那樣傳遞表達式,也可以傳遞用大括號包起來的代碼塊。
借助下面的被測函數:
測試程序如下:
編譯運行效果如下:
容易想到,gtest的這些異常測試宏是用C++的try。。。catch語句來實現的:
如果把上圖中Visual C++的編譯選項/EHsc換成/EHa,try 。。。 catch就可以同時支持C++風格的異常和Windows系統的結構化異常(SEH)。這樣,即使刪掉divide函數里的if判斷,測試代碼的EXPECT_ANY_THROW宏也會成功捕獲異常。
遺憾的是,目前僅使用這些測試宏無法得到獲得被拋出異常的詳細信息(如divide函數中的報錯文本),這和gtest自身不愿意使用C++異常有關。
四、值參數化測試
有些時候,我們需要對代碼實現的功能使用不同的參數進行測試,比如使用大量隨機值來檢驗算法實現的正確性,或者比較同一個接口的不同實現之間的差別。gtest把“集中輸入測試參數”的需求抽象出來提供支持,稱為值參數化測試(Value Parameterized Test)。
值參數化測試包括4個步驟:
1、從gtest的TestWithParam模板類派生一個類(記為C),模板參數為需要輸入的測試參數的類型。由于TestWithParam本身是從Test派生的,所以C就成了一個測試固件類。
2、在C中,可以實現諸如SetUp、TearDown等方法。特別地,測試參數由TestWithParam實現的GetParam()方法依次返回。
3、使用TEST_P(而不是TEST_F)定義測試。
4、使用INSTANTIATE_TEST_CASE_P宏集中輸入測試參數,它接受3個參數:任意的文本前綴,測試類名(這里即為C),以及測試參數值序列。gtest框架依次使用這些參數值生成測試固件類實例,并執行用戶定義的測試。
gtest提供了專門的模板函數來生成參數值序列,如下表所示:
寫個小程序試一下。假設我們實現了一種快速累加算法,希望使用另一種直觀算法進行正確性校驗。算法實現和測試代碼如下:
測試程序如下:
注意TestWithParam的模板參數設置為unsigned類型,而在代碼倒數第2行,兩個常量值都加了u后綴來指定為unsigned類型。熟悉C++的讀者應該知道,模板函數在進行類型推斷(deduction)時匹配相當嚴格,不像普通函數那樣允許類型提升(promotion)。如果上面省略u后綴,就會造成編譯錯誤。當然還可以顯式指定模板參數:testing::Range(1, 1000)。
原文轉自:http://www.anti-gravitydesign.com