爲啥要用GoogleTest呢?html
googletest 是由測試技術Team 開發的帶有google 特殊的需求和限制的測試框架。git
無論你在什麼平臺上寫C++代碼,googleTest 能夠幫助你實現任何類型的測試,不只僅是單元測試github
那麼是什麼成就了一個好的測試,googletest爲何能適用? we believe:express
1. 測試必須是獨立的,而且是能夠重複的。debug 很是痛苦由於發現 一個測試成功失敗依賴於其餘測試。windows
googleTest 經過在不一樣的object上運行test,起到了隔離測試的效果。當一個測試失敗時,googletest allow you 運行在一個隔離的環境裏作快速debug。安全
2. Tests 應當合理的組織起來,以反映 測試代碼的 結構。googletest 把相關的的測試組織起來,而且能夠共享 數據和子程序。架構
這種共同模式很容易識別而且很容易維護測試case。一致性在人們切換Projects 而且在新的code base 上工做時會更有效框架
3. 測試必須是便攜式的(portable)和 可重用的。Google 有不少平臺中立的(platform-neutral)代碼,那麼其測試代碼也應該是平臺中立的。GoogleTest在不一樣的平臺上工做。不一樣的編譯器(gcc, icc, and MSVC), with or without exceptions, so googletest tests can easily work with a variety of configurations.ide
4.當測試失敗時,應該提供關於問題更多詳細的信息。googletest在第一個test失敗時並不中止工做。它只是中止當前測試,並繼續下一個測試。You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.函數
5. testing framework 把測試 做者從 瑣事中解放出來,讓他們專一於測試的內容。googletest 自動跟蹤全部定義的case,不須要 user枚舉並運行他們
6. 測試須要快,googletest能夠幫助你在不一樣的測試中重用共享的資源。and pay for the set-up/tear-down only once, without making tests depend on each other.
由於googleTest 是基於如今最流行的 xUnit 架構的,you'll feel right at home( 很地道的用法)若是你使用過Junit 或者PyUnit.若是沒使用過花個10分鐘學一下基礎,就能夠開始了。
Note: 對於 Test,Test Case and Test Suite 這幾個術語有幾個不一樣的定義,你可能會產生混淆。
歷史上,googletest 使用 Test Case 來表示 一組測試的集合,然而 目前公開的包含 ISTQB 和 不一樣的軟件質量的專業書籍用 Test Suite 來定義此。
googleTest 裏面使用的術語 Test 在 ISTQB裏面稱爲Test Case.
Test 術語是很廣的定義,包含了ISTQB裏的 Test Case的定義,因此這不是一個很大的問題。 可是 GoogleTest 裏面使用的Test Case就是一個有矛盾的術語,於是會讓人產生困惑。
GoogleTest 最近開始用 Test Suite來替換 Test Case。推薦使用 TestSuite* 的API.老的 TestCase* API 漸漸的被棄用而且被重構。
Meaning | googletest Term | ISTQB Term |
---|---|---|
Exercise a particular program path with specific input values and verify the results | TEST() | Test Case |
當使用googletest,從寫assertions開始,assertion 用來check 什麼 condition是 true。 An assertion 的結果能夠是 success, nonfatal failure 或者 fatal failure. 若是 fatal failure 發生,當前function 就終止;不然 程序繼續正常運行
Tests使用 assertions 來驗證 被測代碼的行爲。若是一個測試crash或者有一個 failed 的 assertion,那麼 it fails;不然succeds.
一個 Test case 包含一個或多個 tests。你應當 組合你的 tests into test cases(這邊應該叫 test suite 吧?)來反映 tested code 的結構。當多個test在一個 test case 想要share 子程序的時候,你能夠把它們放到 test fixture 類裏面。
一個 Test program 能夠包含多個 test cases。
咱們開始解釋如何寫一個 test program,從每一個單獨的 assertion 到構建test 和 test cases。
googletest assertions 相似於函數調用的宏。你可使用 assertions 對要測試的類和函數進行斷言。當一個 assertion 失敗。googletest 打印了 assertion的源文件和行號的位置,而且還有失敗信息。你也能夠提供定製的失敗信息。這條信息會被加到googletest 的信息裏面。
assertion成對出現,對於同一個 function有不一樣的影響。 ASSERT_* 版本失敗時產生fatal failure,而且終止當前的函數。EXPECT_* 版本產生 nonfatal failures,不終止當前的函數。 一般 EXPECT_* 更推薦使用。由於你能夠在一個test裏面產生多個 failure。然而,若是繼續當前測試沒有意思時,你就得用 ASSERT_*
由於一個 failed ASSERT_* 從當前函數中立馬返回,也許會提過 clean-up code,可能會引發內存泄漏。取決於泄漏的性質,這個也許值得修復,也許不值得修復。若是是 assertion 致使的內存泄漏就不值得修。
要提供定製的failure 信息,simply 使用 << 操做符,例子:
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; }
任何能夠經過 ostream 輸出的均可以 streamed to 一個 assertion 宏-- 特別是 C 字符串 和 string 對象。若是一個寬的字符(windowsUNICODE模式下的wchar_t*,TCHAR*或者 std::wstring) 被 streamed 到一個斷言上,打印時會被轉換成 UTF-8。
下面的斷言爲一個基礎的 true/false 狀況的測試
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); |
EXPECT_TRUE(condition); |
condition is true |
ASSERT_FALSE(condition); |
EXPECT_FALSE(condition); |
condition is false |
Availability: Linux, Windows, Mac.
下面的斷言描述了比較兩個值的斷言
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_EQ(val1, val2); |
EXPECT_EQ(val1, val2); |
val1 == val2 |
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 |
若是先後兩個值是不能夠比較的,就會獲得一個編譯錯誤。
過去咱們要求 參數要支持<< 符號,可是如今不須要了。若是<< 被支持,當斷言失敗時,會被調用去打印參數。
不然googletest 會嘗試用最好的方法去打印它們。更多詳情請參考 recipe
這些斷言能夠和user-defined類型一塊兒工做,可是隻在你定義的相對應的 比較運算符(e.g. ==,<,etc).由於這不被Google C++ style 所鼓勵。你也許可使用 ASSERT_TRUE() 或者 EXPECT_TRUE()來斷言比較用戶自定義類型的值。
然而,當有可能時,ASSERT_EQ(actual,expected) 更好於 ASSERT_TRUE(actual == expected), 由於 前者會在失敗時告訴你 actual 和 expected 的值。
參數常常僅僅被評估一次。所以,參數有些反作用也是能夠的。然而,和任何普通的C/C++ 函數相比較,參數的評估順序是未定義的(i.e.編譯器自自由選擇順序 )
因此你的code應該不依賴於任何特定的參數評價順序。
ASSERT_EQ()使用的是指針比較。若是使用兩個Cstring比較,它測試的是是否這兩個string使用的是同一地址,而不是是否兩值相等。所以若是你想比較兩個字符串的值,請使用ASSERT_STREQ(),稍後討論該內容。尤爲是使用C string 和 NULL進行比較ASSERT_STREQ(c_string, NULL)。
當比較兩個指針的時候,記得用 *_EQ(ptr, nullptr) 和 *_NE(ptr, nullptr) 而不用 *_EQ(ptr, NULL) 和 *_NE(ptr, NULL)。 由於 nullptr 是類型符號而NULL 不是,See FAQ for more details.
若是你使用浮點數比較 See Advanced googletest Topics for details.
Historical note: Before February 2016 *_EQ
had a convention of calling it as ASSERT_EQ(expected, actual)
, so lots of existing code uses this order. Now *_EQ
treats both parameters in the same way.
這組斷言比較兩個 C string。 若是你想比較兩個string object,使用 EXPECT_EQ 和 EXPECT_NE等等
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(str1, str2); |
EXPECT_STREQ(str1, str2); |
the two C strings have the same content |
ASSERT_STRNE(str1, str2); |
EXPECT_STRNE(str1, str2); |
the two C strings have different contents |
ASSERT_STRCASEEQ(str1, str2); |
EXPECT_STRCASEEQ(str1, str2); |
the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1, str2); |
EXPECT_STRCASENE(str1, str2); |
the two C strings have different contents, ignoring case |
Note that "CASE"在一個 assertion 名字裏面意味着 case被忽略了。 一個 NULL 指針和一個空字符串 被認爲是不同的
*STREQ* 和 *STRNE* 一樣也接受 C字符串(wchar_t *). 若是 一個比較 兩個 寬字符的斷言失敗了,它們的值被打印成UTF-8 的 短字符串
See also: For more string comparison tricks (substring, prefix, suffix, and regular expression matching, for example), seethis in the Advanced googletest Guide.
簡單的測試
1. 使用 TEST()宏 來定義和命名測試 function,這些是普通的C++函數而且不返回值。
2. 在這個函數裏,和其餘任何你想要包含的C++ 表達式,使用各類各樣的googletest 斷言去check values
3. 測試的結果由斷言所決定;若是測試裏面的任何斷言失敗了(要麼fatally 要麼 non-fatally),或者若是測試crashes,整個測試失敗。不然,成功
TEST(TestSuiteName, TestName) {
... test body ...
}
TEST() 參數從 general 到 specific. 第一個參數是test case 的名字,第二個參數是test case裏面的 test的名字。 二者的名字都要是有效的C++ identifiers,而且不能有underscore(_)。一個測試的全名包含它 test case和其 individual name。Tests from different test cases can have the same individual name.
例若有一個簡單的 integers function:
int Factorial(int n); // Returns the factorial of n
對於它的測試case 可能像這個樣子:
// Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(Factorial(0), 1); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(Factorial(1), 1); EXPECT_EQ(Factorial(2), 2); EXPECT_EQ(Factorial(3), 6); EXPECT_EQ(Factorial(8), 40320); }
googletest 經過 test cases來組合這些 test,因此說 邏輯上相關的tests應該在同一個test case裏面;換句話說, TEST()第一個參數應該是相同的,上面的例子裏面,咱們有兩個tests,HandlesZeroInput 和 HandlesPositiveInput, 它們同屬於同一個 test case FactorialTest。
命名 testcases 和 tests,你應該遵循必定的規則 naming functions and classes。
若是你發現你寫兩個或者多個 tests 用到了相同的數據,你可使用 test fixture。它可讓多個tests使用相同的配置。
To create a fixture:
1. 集成 ::testing:Test. 使用 protected 字段:咱們能夠訪問子類裏的 fixture 成員。
2. 在類裏面,申明你想要使用的任何對象。
3. 必要的時候,寫一個默認構造函數或者 SetUp() 函數 來準備每一個 test的對象。記住拼寫 SetUp() 不是Setup()
Use override
in C++11 to make sure you spelled it correctly
4.必要的時候,寫一個析構函數或者TearDown()釋放你在SetUp() 裏面分配的資源,想知道何時使用 constructor/destructor 何時使用etUp()/TearDown(), read this FAQ entry
5. 有必要定義你tests裏面的子函數供share。
定義了 fixture,想要在test裏面訪問 fixture的對象和子函數,就得使用TEST_F() 而不是TEST()
TEST_F(TestSuiteName, TestName) {
... test body ...
}
和 TEST()同樣,第一個參數是 test case 的名字,可是對於TEST_F()來講第一個參數必須爲 test fixture class. 你也許已經猜到了:_F 就是 fixture 的意思。
Unfortunately, C++ macro 系統不容許咱們建立一個單獨的宏處理不一樣的tests. 使用錯誤的宏會致使編譯錯誤。
此外,你必須在使用TEST_F() 以前先定義 一個 test fixture, 不然 你將會收到 compiler 錯誤 「virtual outside class declaration"
每個 用TEST_F() 定義的 test,googletest 會在運行時建立一個新的 test fixture,馬上經過 SetUp() 初始化,運行測試,經過調用 TearDown()來清理測試,最後刪除test fixture。注意 在 test case 裏面的不一樣tests擁有的時不一樣的 test fixture 對象。 googletest 常常在 建立下一個 test fixture 前先刪除一個。 googletest 對於多個 tests不重複使用同一個 test fixture。 任何對於其中一個 test 的改變不影響其餘的 tests。
舉一個例子, 咱們寫了一個 命名爲 Queue 的FIFO queue的 tests,接口以下:
template <typename E> // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... };
首先,定義一個 fixture 類。根據命名的傳統,FooTest實質上被測的類就是Foo。咱們定義QueueTest.
class QueueTest : public ::testing::Test { protected: void SetUp() override { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // void TearDown() override {} Queue<int> q0_; Queue<int> q1_; Queue<int> q2_; };
這個例子裏面,TearDown() 是不須要的由於咱們不須要在每一個test 結束後都清理,咱們已經經過析構函數實現了這一功能。
如今咱們就能夠在TEST_F() 裏面使用 這個 fixture
TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(q0_.size(), 0); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(n, nullptr); n = q1_.Dequeue(); ASSERT_NE(n, nullptr); EXPECT_EQ(*n, 1); EXPECT_EQ(q1_.size(), 0); delete n; n = q2_.Dequeue(); ASSERT_NE(n, nullptr); EXPECT_EQ(*n, 2); EXPECT_EQ(q2_.size(), 1); delete n; }
上面的測試case 既用到了 ASSERT_* 也用到了 EXPECT_* 斷言。 使用EXPECT_*在斷言失敗以後能夠 查看更多錯誤的信息。 若是斷言以後的信息沒有意義則使用ASSERT_*。
例如, 在Dequeue 的第二個斷言中 =ASSERT_NE(nullptr,n)=, as we need to dereference the pointer n later, which would lead to a segfault when n is NULL.
當這些 tests 運行的時候,以下過程執行了:
1. googletest 構造了 QueueTest 對象(let‘s call it t1).
2. t1.SetUp() 初始化 t1
3. t1 的 第一個 test(IsEmptyInitially) 運行
4. t1.TearDown() 在 test 結束時進行 清理.
5. t1 被析構
6.以上步驟在另外一個 QueueTest 對象會被重複,此次運行的時 DequeueWorks test。
TEST() 和 TEST_F() 隱式向googletest 註冊了。因此說 和其餘的C++ 測試框架不同的是,你沒必要要在運行時從新把test 從新按順序列出來。
當被調用時, RUN_ALL_TESTS() 宏:
1. 保存全部 googletest flag 的狀態
爲第一條test 建立 test fixture 對象
經過 SetUp() 初始化
基於 fixture 運行 tests
經過TearDown() 清理 fixture
刪除 fixture
從新存儲 全部 googletest flags 的狀態
爲下一條測試執行上面一樣的步驟,直到全部tests 執行完。
若是 fatal failure 發生了,隨後的步驟會被跳過。
IMPORTANT: 你不能忽略 RUN_ALL_TESTS() 的返回值,不然你會達到編譯錯誤。這樣設計的合理之處在於 自動化測試的服務經過 exit code 來判斷其執行是否成功,而不是
經過 其 stdout/stderr 輸出。所以你的main 函數必須有RUN_ALL_TESTS() 的返回值
而且,你應當只調用 RUN_ALL_TESTS()一次。屢次調用可能會和某些高級功能( thread-safe death tests)相沖突,而且這些在這時不支持的
寫你本身的 main 函數,應當有 RUN_ALL_TESTS() 的返回值。
#include "this/package/foo.h" #include "gtest/gtest.h" namespace { // The fixture for testing class Foo. class FooTest : public ::testing::Test { protected: // You can remove any or all of the following functions if its body // is empty. FooTest() { // You can do set-up work for each test here. } ~FooTest() override { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: void SetUp() override { // Code here will be called immediately after the constructor (right // before each test). } void TearDown() override { // Code here will be called immediately after each test (right // before the destructor). } // Objects declared here can be used by all tests in the test case for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const std::string input_filepath = "this/package/testdata/myinputfile.dat"; const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
::testing:InitGoogleTest() 函數 從命令行解析 googletest flags, 移除 全部已經識別的 flags。這容許用戶經過不一樣的flags 來控制 測試程序的行爲,咱們將在 AdvancedGuide裏介紹。你必須在 調用 RUN_ALL_TESTS() 以前調用這個函數。不然flags 不會被合理的初始化。
在 Windows上,InitGoogleTest() 也能夠在 wide string 模式下運行,因此這也會在 UNICODE模式下編譯。
可是也許你想寫這麼多在main 函數裏面太費事了?咱們也徹底贊成你的想法,那就是爲何GoogleTest提供了main函數的記本實施。若是這知足你的須要,把你的測試和gtest_main庫創建連接,你就能夠開始啦!
GoogleTest 按照線程安全設計的。有 pthreads library 的狀況下,系統上的執行是線程安全的。 目前在你的系統上從多個線程使用Google Test 斷言是不安全的。在大多數的tests裏面這不是一個問題,由於 assertion 都是在主線程裏面的。If you want to help, you can volunteer to implement the necessary synchronization primitives in gtest-port.h
for your platform.