from : http://www.cnblogs.com/jycboy/p/6057677.htmlhtml
在用google test寫測試項目以前,須要先編譯gtest到library庫並將測試與其連接。咱們爲一些流行的構建系統提供了構建文件: msvc/
for Visual Studio, xcode/
for Mac Xcode, make/
for GNU make, codegear/
for Borland C++ Builder.java
若是你的構建系統不在這個名單上,在googletest根目錄有autotools的腳本(不推薦使用)和CMakeLists.txt
CMake(推薦)。你能夠看看make / Makefile來了解如何編譯Google Test(基本上你想在頭文件中使用GTEST_ROOT和GTEST_ROOT / include來編譯src / gtest-all.cc路徑,其中GTEST_ROOT是Google測試根目錄)。git
一旦你可以編譯google test庫,您應該爲您的測試程序建立一個項目或構建目標。Make sure you have GTEST_ROOT/include
in the header search path so that the compiler can find "gtest/gtest.h"
when compiling your test.把google test庫加到你的測試項目中(好比:在VS中在gtest.vcproj上添加依賴)。github
當使用谷歌測試,您首先要寫斷言,斷言是檢查條件是否爲真的語句。一個斷言的結果能夠是成功,非致命性失敗,或致命的失敗。若是一個致命失敗出現,它會終止當前的函數;不然程序繼續正常運行。正則表達式
測試使用斷言驗證代碼的行爲。若是一個測試崩潰或者有一個失敗的斷言,那麼失敗;不然成功。xcode
一個測試用例包含一個或多個測試。 您應該將測試分組爲反映測試代碼結構的測試用例。當測試用例中的多個測試須要共享公共的對象和子程序時,你能夠把它們放進一個test fixture class(測試夾具類)。安全
一個測試程序能夠包含多個測試用例。框架
如今咱們將解釋如何編寫測試程序,從單個斷言級別開始,並構建測試和測試用例。ide
Google Test斷言是相似於函數調用的宏。您能夠經過對其行爲進行斷言來測試類或函數。當斷言失敗時,Google Test會打印斷言的源文件和行號位置以及失敗消息。您還能夠提供自定義失敗消息,該消息將附加到Google測試的信息中。函數
斷言是成對的,測試同一件事,但對當前函數有不一樣的影響。 ASSERT_ *版本在失敗時會生成致命錯誤,並停止當前函數。 EXPECT_ *版本生成非致命性故障,不會停止當前函數。一般優先使用EXPECT_ *,由於它們容許在測試中報告多個故障。可是,若是失敗時函數繼續運行沒有意義,則應使用ASSERT_ *。
由於失敗的ASSERT_ *當即從當前函數返回,可能跳過其後的清理代碼,它可能致使資源泄漏。根據泄漏的性質,它可能值得修復也可能不值得修復--因此把這個記在內心,若是你有一個堆檢測錯誤須要注意是什麼致使的。
要提供自定義失敗消息,只需使用<<運算符或一系列此類運算符將其流式傳輸到宏中便可。一個例子:
1
2
3
4
5
|
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;
}
|
示例:
1
|
EXPECT_EQ(
0
, strcmp(s.c_string(), kHelloString2)) <<
"s.c_string:"
<< s.c_string() <<
" kHelloString:"
<< +kHelloString ;
|
任何能夠流式傳輸到ostream的東西均可以流式傳輸到斷言宏,特別是C字符串和字符串對象。 若是一個寬字符串(Windows上的wchar_t *,TCHAR *在UNICODE模式下,或者std :: wstring)被流化到一個斷言,當打印時它將被轉換爲UTF-8。
這些斷言作基本的真/假條件測試。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE( condition) ; |
EXPECT_TRUE( condition) ; |
condition is true |
ASSERT_FALSE( condition) ; |
EXPECT_FALSE( condition) ; |
condition is false |
記住,當它們失敗時,ASSERT_ *產生致命失敗並從當前函數返回,而EXPECT_ *產生非致命失敗,容許函數繼續運行。 在任一狀況下,斷言失敗意味着其包含的測試失敗。
本節介紹比較兩個值的斷言。
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 |
在發生故障時,Google測試同時打印val1和val2。
值參數經過斷言的比較運算符必須能夠比較,不然會出現編譯錯誤。咱們曾經要求參數支持<<運算符,用於流傳輸到ostream,但從v1.6.0它再也不須要(若是支持<<,則會在斷言失敗時調用它來打印參數;不然Google Test將嘗試以最佳方式打印它們。有關更多詳細信息和如何自定義參數的打印,請參閱此Google Mock recipe.。
這些斷言可使用用戶定義的類型,可是隻有當你定義了相應的比較運算符(例如==,<,etc)。若是定義了相應的操做符,則更喜歡使用ASSERT _ *()宏,由於它們不只會打印比較結果,並且還會打印出兩個操做數。
參數老是隻計算一次。所以,參數有反作用不要緊。然而,與任何普通的C / C ++函數同樣,參數的求值順序是未定義的(即編譯器能夠自由選擇任何順序),你的代碼不該該依賴於任何特定的參數求值順序。
ASSERT_EQ()指針的指針相等。若是在兩個C字符串上使用,它會測試它們是否在同一個內存位置,而不是它們具備相同的值。所以,若是你想比較C字符串(例如const char *)的值,使用ASSERT_STREQ(),稍後將會描述。特別地,要斷言C字符串爲NULL,請使用ASSERT_STREQ(NULL,c_string)。可是,要比較兩個字符串對象,應該使用ASSERT_EQ。
本節中的宏適用於窄和寬字符串對象(string和wstring)。
歷史記錄:2016年2月以前* _EQ有一個約定,稱爲ASSERT_EQ(expected,actual),因此不少現有的代碼使用這個順序。 如今* _EQ以相同的方式處理這兩個參數。
該組中的斷言比較兩個C字符串的值。 若是要比較兩個字符串對象,請改用EXPECT_EQ,EXPECT_NE和etc。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ( str1, str2); |
EXPECT_STREQ( str1, _str_2); |
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( 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 content, ignoring case |
注意,斷言名中的「CASE」表示忽略大小寫。
* STREQ *和* STRNE *也接受寬C字符串(wchar_t *)。 若是兩個寬字符串的比較失敗,它們的值將打印爲UTF-8窄字符串。
NULL指針和空字符串被認爲是不一樣的。
可用性:Linux,Windows,Mac。
另請參閱:有關更多字符串比較技巧(例如,子字符串,前綴,後綴和正則表達式匹配),請參見高級Google測試指南(Advanced Google Test Guide.)。
建立測試:
1.使用TEST()宏來定義和命名測試函數,這些是不返回值的普通C++函數。
2.在此函數中,連同要包括的任何有效的C++語句,使用各類Google Test斷言來檢查值。
3.測試的結果由斷言肯定; 若是測試中的任何斷言失敗(致命或非致命),或者若是測試崩潰,則 整個測試失敗。 不然,它成功。
1
2
3
|
TEST(test_case_name, test_name) {
... test body ...
}
|
TEST()參數從通常到特定。 第一個參數是測試用例的名稱,第二個參數是測試用例中的測試名稱。 這兩個名稱必須是有效的C ++標識符,而且它們不該包含下劃線(_)。 測試的全名由其包含的測試用例及其我的名稱組成。來自不一樣測試用例的測試能夠具備相同的我的名稱。
例如,讓咱們使用一個簡單的整數函數:
1
|
int
Factorial(
int
n);
// Returns the factorial of n;n!
|
此函數的測試用例可能以下所示:
1
2
3
4
5
6
7
8
9
10
11
12
|
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(
1
, Factorial(
0
));
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(
1
, Factorial(
1
));
EXPECT_EQ(
2
, Factorial(
2
));
EXPECT_EQ(
6
, Factorial(
3
));
EXPECT_EQ(
40320
, Factorial(
8
));
}
|
Google Test經過測試用例對測試結果進行分組,所以邏輯相關的測試應該在同一測試用例中; 換句話說,它們的TEST()的第一個參數應該是相同的。 在上面的例子中,咱們有兩個測試,HandlesZeroInput和HandlesPositiveInput,屬於同一個測試用例FactorialTest。
若是你發現本身寫了兩個或更多的測試來操做相似的數據,你可使用測試夾具。它容許您爲幾個不一樣的測試重複使用相同的對象配置。
要建立夾具,只需:
1.從:: testing :: Test派生一個類。 使用protected:或public:開始它的主體,由於咱們想從子類 訪問fixture成員。
2.在類中,聲明你打算使用的任何對象。
3.若是須要,能夠編寫默認構造函數或SetUp()函數來爲每一個測試準備對象。 一個常見的錯誤是 拼寫SetUp()爲Setup()與一個小u -- 不要讓這種狀況發生在你身上。
4.若是須要,寫一個析構函數或TearDown()函數來釋放你在SetUp()中分配的任何資源。 要 學習何時應該使用構造函數/析構函數,當你應該使用SetUp()/ TearDown()時,請閱讀這個 FAQ entry.。
5.若是須要,定義要分享的測試的子程序。
當使用夾具時,使用TEST_F()而不是TEST(),由於它容許您訪問測試夾具中的對象和子程序:
1
2
3
|
TEST_F(test_case_name, test_name) {
... test body ...
}
|
和TEST()同樣,第一個參數是測試用例名,
可是對於TEST_F()第一個參數必須是測試夾具類的名稱。 你可能猜到了:_F是夾具。
不幸的是,C ++宏系統不容許咱們建立一個能夠處理兩種類型的測試的宏。 使用錯誤的宏會致使編譯器錯誤。
另外,在TEST_F()中使用它以前,你必須首先定義一個測試夾具類,不然將獲得編譯器錯誤「virtual outside class declaration」。
對於使用TEST_F()定義的每一個測試,Google Test將:
1.在運行時建立一個新的測試夾具
2.當即經過SetUp()初始化,
3.運行測試
4.經過調用TearDown()清除
5.刪除測試夾具。 請注意,同一測試用例中的不一樣測試具備不一樣的測試夾具對象,Google測試始 終會刪除測試夾具,而後再建立下一個測試夾具。 Google測試不會爲多個測試重複使用相同的 測試夾具。一個測試對夾具的任何更改不會影響其餘測試。
例如,讓咱們爲名爲Queue的FIFO隊列類編寫測試,它有如下接口:
1
2
3
4
5
6
7
8
9
|
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
;
...
};
|
首先定義一個夾具類。按照慣例,你應該給它名稱FooTest,其中Foo是被測試的類。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class
QueueTest :
public
::testing::Test {
protected
:
virtual
void
SetUp() {
q1_.Enqueue(
1
);
q2_.Enqueue(
2
);
q2_.Enqueue(
3
);
}
// virtual void TearDown() {}
Queue<
int
> q0_;
Queue<
int
> q1_;
Queue<
int
> q2_;
};
|
在這種狀況下,不須要TearDown(),由於咱們沒必要在每次測試後清理,除了析構函數已經作了什麼。
如今咱們將使用TEST_F()和這個夾具編寫測試。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(
0
, q0_.size());
}
TEST_F(QueueTest, DequeueWorks) {
int
* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(
1
, *n);
EXPECT_EQ(
0
, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(
2
, *n);
EXPECT_EQ(
1
, q2_.size());
delete n;
}
|
上面使用ASSERT_ *和EXPECT_ *斷言。 經驗法則( The rule of thumb )是當你但願測試在斷言失敗後繼續顯示更多錯誤時使用EXPECT_ *,或是在失敗後繼續使用ASSERT_ *沒有意義。 例如,Dequeue測試中的第二個斷言是ASSERT_TRUE(n!= NULL),由於咱們須要稍後解引用指針n,這將致使n爲NULL時的segfault。
當這些測試運行時,會發生如下狀況:
1.Google Test構造了一個QueueTest對象(咱們稱之爲t1)。
2.t1.SetUp()初始化t1。
3.第一個測試(IsEmptyInitially)在t1上運行。
4.t1.TearDown()在測試完成後清理。
5.t1被析構。
6.以上步驟在另外一個QueueTest對象上重複,此次運行DequeueWorks測試。
TEST()和TEST_F()用Google Test隱式註冊他們的測試。 所以,與許多其餘C ++測試框架不一樣,您沒必要從新列出全部定義的測試以運行它們。
定義測試後,可使用RUN_ALL_TESTS()運行它們,若是全部測試成功則返回0,不然返回1。 請注意,RUN_ALL_TESTS()運行連接單元中的全部測試 - 它們能夠來自不一樣的測試用例,甚至是不一樣的源文件。
調用時,RUN_ALL_TESTS()宏:
1. 保存全部Google測試標記的狀態。
2. 爲第一個測試建立測試夾具對象。
3. 經過SetUp()初始化它。
4. 在fixture對象上運行測試。
5. 經過TearDown()清除夾具。
6. 刪除夾具。
7. 恢復全部Google測試標誌的狀態。
8. 重複上述步驟進行下一個測試,直到全部測試運行結束。
此外,若是測試夾具的構造函數在步驟2中產生致命故障,則步驟3-5沒有意義,所以它們被跳過。 相似地,若是步驟3產生致命故障,則將跳過步驟4。
重要:您不能忽略RUN_ALL_TESTS()的返回值,不然gcc將給您一個編譯器錯誤。 此設計的基本原理是自動測試服務基於其退出代碼而不是其stdout / stderr輸出來肯定測試是否已經過; 所以您的main()函數必須返回RUN_ALL_TESTS()的值。
此外,您應該只調用一次RUN_ALL_TESTS()。 屢次調用它會與一些高級Google測試功能(例如線程安全死亡測試)衝突,所以不受支持。
你能夠從這個樣板開始:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#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.
}
virtual ~FooTest() {
// 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:
virtual
void
SetUp() {
// Code here will be called immediately after the constructor (right
// before each test).
}
virtual
void
TearDown() {
// 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
string input_filepath =
"this/package/testdata/myinputfile.dat"
;
const
string output_filepath =
"this/package/testdata/myoutputfile.dat"
;
Foo f;
EXPECT_EQ(
0
, f.Bar(input_filepath, output_filepath));
}
// 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()函數解析Google測試標誌的命令行,並刪除全部已識別的標誌。 這容許用戶經過各類標誌控制測試程序的行爲,咱們將在AdvancedGuide中介紹。 在調用RUN_ALL_TESTS()以前必須調用此函數,不然標誌將沒法正確初始化。
在Windows上,InitGoogleTest()也適用於寬字符串,所以它也能夠在以UNICODE模式編譯的程序中使用。
但也許你認爲編寫全部這些main()函數是太多的工做? 咱們徹底贊成你的見解,這就是爲何Google Test提供了main()的基本實現。 若是它適合你的須要,而後只是連接你的測試與gtest_main庫。
若是你把你的測試放入一個庫,你的main()函數在不一樣的庫或在你的 .exe文件中,這些測試將不會運行。 緣由是Visual C ++中的一個錯誤。 當您定義測試時,Google測試會建立一些靜態對象來註冊它們。 這些對象沒有從其餘地方引用,但它們的構造函數仍然應該運行。 當Visual C ++連接器發現庫中沒有從其餘地方引用時,它會拋出該庫。 您必須經過主程序中的測試來引用您的庫,以防止連接器丟棄它。 這裏是如何作到的。 在你的庫代碼中聲明一個函數:
。。。。。省略啦,若是用VC再來看。
恭喜! 您已學習了Google測試基礎知識。 您能夠開始編寫和運行Google Test測試,閱讀一些示例,或繼續閱讀AdvancedGuide,其中介紹了更多有用的Google測試功能。
Google測試旨在線程安全。 在pthreads庫可用的系統上,實現是線程安全的。 目前,在其餘系統(例如Windows)上同時使用兩個線程的Google Test斷言是不安全的。 在大多數測試中,這不是一個問題,由於一般斷言是在主線程中完成的。 若是你想幫助,你能夠志願爲您的平臺在gtest-port.h中實現必要的同步原語。