前幾個(gè)月Google開源了它的測試框架,自稱其旗下的上千個(gè)項(xiàng)目都在使用它。今天我們就用它來嘗嘗鮮吧?:-)
安裝:
下載Google C++ Testing Framework,解壓...
VC2005:
直接打開msvc\gtest.vcproj或msvc\gtest.sln,直接編譯即可。
Linux/Unix下的GCC:
傳統(tǒng)過程:./configure make
Mingw:
BCC:
用Mingw和BCB6編譯需要修改一些代碼,過幾天我會(huì)上傳到www.cppprog.com網(wǎng)站上。
使用:
首先#include <gtest/gtest.h>,當(dāng)然工程的頭文件路徑要設(shè)置正確
1.簡單測試TEST
假如我寫了個(gè)函數(shù),是計(jì)算階乘的:
1. int Factorial( int n )
2. {
3. if(n==2) return 100;
4. return n<=0? 1 : n*Factorial(n - 1);
5. }
6.
7. TEST(TestFactorial, ZeroInput)
8. {
9. EXPECT_EQ(1, Factorial(0));
10. }
11. TEST(TestFactorial, OtherInput)
12. {
13. EXPECT_EQ(1, Factorial(1));
14. EXPECT_EQ(2, Factorial(2));
15. EXPECT_EQ(6, Factorial(3));
16. EXPECT_EQ(40320, Factorial(8));
17. }
18. int main(int argc, TCHAR* argv[])
19. {
20. testing::InitGoogleTest(&argc,argv);
21. RUN_ALL_TESTS();
22. std::cin.get();
23. return 0;
24. }
25.
運(yùn)行結(jié)果:

瞧:測試框架指出:TestFactorial.ZeroInput運(yùn)行OK,運(yùn)行OtherInput時(shí)出現(xiàn)三次結(jié)果和預(yù)期不符。
2.多個(gè)測試場景需要相同數(shù)據(jù)配置的情況,用TEST_F
1.
2. typedef std::basic_string<TCHAR> tstring;
3. struct FooTest : testing::Test {
4.
5. tstring strExe;
6.
7. FooTest() {}
8. virtual ~FooTest() {}
9.
10. virtual void SetUp() {
11.
12. strExe.resize(MAX_PATH);
13. GetModuleFileName(NULL, &strExe[0], MAX_PATH);
14. }
15. virtual void TearDown() { }
16. };
17. tstring getfilename(const tstring &full)
18. {
19. return full.substr(full.rfind(_T('\\')));
20. }
21. tstring getpath(const tstring &full)
22. {
23. return full.substr(0, full.rfind(_T('\\')));
24. }
25. TEST_F(FooTest, Test_GFN)
26. {
27. EXPECT_STREQ(_T("Project1.exe"), getfilename(strExe).c_str());
28. }
29. TEST_F(FooTest, Test_GP)
30. {
31. EXPECT_STREQ(_T("D:\\Code\\libs\\google\\gtest-1.2.1\\BCC_SPC\\bcc\\ex"), getpath(strExe).c_str());
32. }
33. int main(int argc, TCHAR* argv[])
34. {
35. testing::InitGoogleTest(&argc,argv);
36. RUN_ALL_TESTS();
37. std::cin.get();
38. return 0;
39. }
運(yùn)行結(jié)果:

瞧,Google C++ 測試框架毫不客氣地指出偶的getfilename返回的字符串比預(yù)期的多了一個(gè)'\\'
快速入門:
Google提供了兩種斷言形式,一種以ASSERT_開頭,另一種以EXPECT_開頭,它們的區(qū)別是ASSERT_*一旦失敗立馬退出,而EXPECT_還能繼續(xù)下去。
斷言列表:
真假條件測試:
致命斷言 | 非致命斷言 | 驗(yàn)證條件 |
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition為真 |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition 為假 |
數(shù)據(jù)對(duì)比測試:
致命斷言 | 非致命斷言 | 驗(yàn)證條件 |
ASSERT_EQ(期望值, 實(shí)際值); | EXPECT_EQ(期望值, 實(shí)際值); | 期望值 == 實(shí)際值 |
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 |
字符串(針對(duì)C形式的字符串,即char*或wchar_t*)對(duì)比測試:
致命斷言 | 非致命斷言 | 驗(yàn)證條件 |
ASSERT_STREQ(expected_str, actual_str); | EXPECT_STREQ(expected_str, actual_str); | 兩個(gè)C字符串有相同的內(nèi)容 |
ASSERT_STRNE(str1, str2); | EXPECT_STRNE(str1, str2); | 兩個(gè)C字符串有不同的內(nèi)容 |
ASSERT_STRCASEEQ(expected_str, actual_str); | EXPECT_STRCASEEQ(expected_str, actual_str); | 兩個(gè)C字符串有相同的內(nèi)容,忽略大小寫 |
ASSERT_STRCASENE(str1, str2); | EXPECT_STRCASENE(str1, str2); | 兩個(gè)C字符串有不同的內(nèi)容,忽略大小寫 |
TEST宏:
TEST宏的作用是創(chuàng)建一個(gè)簡單測試,它定義了一個(gè)測試函數(shù),在這個(gè)函數(shù)里可以使用任何C++代碼并使用上面提供的斷言來進(jìn)行檢查。
TEST的第一個(gè)參數(shù)是測試用例名,第二個(gè)參數(shù)是測試用例中某項(xiàng)測試的名稱。一個(gè)測試用例可以包含任意數(shù)量的獨(dú)立測試。這兩個(gè)參數(shù)組成了一個(gè)測試的全稱。
就前面的例子來說:
我們要測試這個(gè)函數(shù):int Factorial(int n); // 返回n的階乘
我們的測試用例是:測試輸入0的情況,測試輸入其它數(shù)據(jù)的情況,于是就有了:
1. TEST(TestFactorial, ZeroInput)
2. {
3. EXPECT_EQ(1, Factorial(0));
4. }
5. TEST(TestFactorial, OtherInput)
6. {
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()的第一個(gè)參數(shù)應(yīng)該是一樣的。在上面的例子中,我們有兩個(gè)測試,ZeroInput和OtherInput,它們都屬于同一個(gè)測試用例TestFactorial。
TEST_F宏:
TEST_F宏用于在多個(gè)測試中使用同樣的數(shù)據(jù)配置,所以它又叫:測試夾具(Test Fixtures)
如果我們的多個(gè)測試要使用相同的數(shù)據(jù)(如前例中,我們的Test_GFN和Test_GP都使用程序自身的完整文件名來測試),就可以采用一個(gè)測試夾具。
要?jiǎng)?chuàng)建測試固件,只需:
1. 創(chuàng)建一個(gè)類繼承自testing::Test。將其中的成員聲明為protected:或是public:,因?yàn)槲覀兿胍獜淖宇愔写嫒A具成員。
2. 在該類中聲明測試中所要使用到的數(shù)據(jù)。
3. 如果需要,編寫一個(gè)默認(rèn)構(gòu)造函數(shù)或者SetUp()函數(shù)來為每個(gè)測試準(zhǔn)備對(duì)象。
4. 如果需要,編寫一個(gè)析構(gòu)函數(shù)或者TearDown()函數(shù)來釋放你在SetUp()函數(shù)中申請(qǐng)的資源。
5. 如果需要,定義你的測試所需要共享的子程序。
當(dāng)我們要使用固件時(shí),使用TEST_F()替換掉TEST(),它允許我們存取測試固件中的對(duì)象和子程序:
TEST_F(test_case_name, test_name) {
... test body ...
}
與TEST()一樣,第一個(gè)參數(shù)是測試用例的名稱,但對(duì)TEST_F()來說,這個(gè)名稱必須與測試夾具類的名稱一樣。
對(duì)于TEST_F()中定義的每個(gè)測試,Google Test將會(huì):
1. 創(chuàng)建一個(gè)全新的測試夾具
2. 通過SetUp()初始化它,
3. 運(yùn)行測試
4. 調(diào)用TearDown()來進(jìn)行清理工作
5. 刪除測試夾具。
注意,同一測試用例中,不同的測試擁有不同的測試夾具。Google Test不會(huì)對(duì)多個(gè)測試重用一個(gè)測試夾具,測試對(duì)測試夾具的改動(dòng)并不會(huì)影響到其他測試。
調(diào)用測試
TEST()和TEST_F()向Google Test隱式注冊(cè)它們的測試。因此,與很多其他的C++測試框架不同,你不需要為了運(yùn)行你定義的測試而將它們?nèi)吭倭谐鰜硪淮巍?
在定義好測試后,你可以通過RUN_ALL_TESTS()來運(yùn)行它們,如果所有測試成功,該函數(shù)返回0,否則會(huì)返回1.注意RUN_ALL_TESTS()會(huì)運(yùn)行你鏈接到的所有測試——它們可以來自不同的測試用例,甚至是來自不同的文件。
當(dāng)被調(diào)用時(shí),RUN_ALL_TESTS()宏會(huì):
1. 保存所有的Google Test標(biāo)志。
2. 為一個(gè)測試創(chuàng)建測試夾具對(duì)象。
3. 調(diào)用SetUp()初始化它。
4. 在固件對(duì)象上運(yùn)行測試。
5. 調(diào)用TearDown()清理夾具。
6. 刪除固件。
7. 恢復(fù)所有Google Test標(biāo)志的狀態(tài)。
8. 重復(fù)上訴步驟,直到所有測試完成。
此外,如果第二步時(shí),測試夾具的構(gòu)造函數(shù)產(chǎn)生一個(gè)致命錯(cuò)誤,繼續(xù)執(zhí)行3至5部顯然沒有必要,所以它們會(huì)被跳過。與之相似,如果第3部產(chǎn)生致命錯(cuò)誤,第4部也會(huì)被跳過。
重要:你不能忽略掉RUN_ALL_TESTS()的返回值,否則gcc會(huì)報(bào)一個(gè)編譯錯(cuò)誤。這樣設(shè)計(jì)的理由是自動(dòng)化測試服務(wù)會(huì)根據(jù)測試退出返回碼來決定一個(gè)測試是否通過,而不是根據(jù)其stdout/stderr輸出;因此你的main()函數(shù)必須返回RUN_ALL_TESTS()的值。
而且,你應(yīng)該只調(diào)用RUN_ALL_TESTS()一次。多次調(diào)用該函數(shù)會(huì)與Google Test的一些高階特性(如線程安全死亡測試thread-safe death tests)沖突,因而是不被支持的。
編寫main()函數(shù)
你可以從下面這個(gè)模板開始:
1. #include "this/package/foo.h"
2. #include <gtest/gtest.h>
3. namespace {
4.
5. class FooTest : public testing::Test {
6. protected:
7.
8.
9. FooTest() {
10.
11. }
12. virtual ~FooTest() {
13.
14. }
15.
16.
17. virtual void SetUp() {
18.
19.
20. }
21. virtual void TearDown() {
22.
23.
24. }
25.
26. };
27.
28. TEST_F(FooTest, MethodBarDoesAbc) {
29. const string input_filepath = "this/package/testdata/myinputfile.dat";
30. const string output_filepath = "this/package/testdata/myoutputfile.dat";
31. Foo f;
32. EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
33. }
34.
35. TEST_F(FooTest, DoesXyz) {
36.
37. }
38. }
39. int main(int argc, char **argv) {
40. testing::InitGoogleTest(&argc, argv);
41. return RUN_ALL_TESTS();
42. }
testing::InitGoogleTest() 函數(shù)負(fù)責(zé)解析命令行傳入的Google Test標(biāo)志,并刪除所有它可以處理的標(biāo)志。這使得用戶可以通過各種不同的標(biāo)志控制一個(gè)測試程序的行為。關(guān)于這一點(diǎn)我們會(huì)在GTestAdvanced中講到。你必須在調(diào)用RUN_ALL_TESTS()之前調(diào)用該函數(shù),否則就無法正確地初始化標(biāo)示。
在Windows上InitGoogleTest()可以支持寬字符串,所以它也可以被用在以UNICODE模式編譯的程序中。
Google test for mingw 下載: http://www.cppprog.com/2009/0101/26.html Google test for bcb 下載: http://www.cppprog.com/2009/0101/27.html
發(fā)表于 @ 2008年12月30日 19:46:00|評(píng)論(13 )|收藏
您的文章已經(jīng)被推薦到CSDN首頁專家專欄欄目,將被更多的CSDN網(wǎng)友閱讀與分享。感謝您對(duì)CSDN博客的支持。
不知道能不能給個(gè)vc的例子,有些地方不是很明白
不知道能不能給個(gè)vc的例子,有些地方不是很明白
不知道能不能給個(gè)vc的例子,有些地方不是很明白
同求vc的例子,最好6.0,^_^
同求vc的例子,最好6.0,^_^
同求vc的例子,最好6.0,^_^
VC是最簡單的,從官網(wǎng)上下載以后里面就自帶了VC的工程文件(包含例子和庫文件),直接打開編譯就可以了。
注意庫文件默認(rèn)是“多線程”而不是“多線程DLL”。
我上面的代碼就是在VC2005里修改的。
至于VC6.0,我沒試過,不過可以考慮去下載我修改的for BCB6.0的代碼,VC6.0應(yīng)該也能編譯通過。
olay105 發(fā)表于2009年1月1日 18:29:28 IP:
總共15個(gè),你知道怎么解決呢? 文章鏈接:http://blog.csdn.net/Waiting4you/archive/2008/12/30/3652350.aspx 發(fā)表時(shí)間:2009年1月1日 18:29:28">舉報(bào)
博主,我是第一次用vs2005,但是在實(shí)驗(yàn)?zāi)愕奈恼轮谐霈F(xiàn)了很多問題,解決了一些,最后還是有一個(gè)棘手的,能幫我解決一下嗎?可能是編譯時(shí)的鏈接問題:error LNK2019: unresolved external symbol "protected: __thiscall testing::Test::Test(void)" (??0Test@testing@@IAE@XZ) referenced in function "public: __thiscall TestFactorial_ZeroInput_Test::TestFactorial_ZeroInput_Test(void)" (??0TestFactorial_ZeroInput_Test@@QAE@XZ) project1.obj
總共15個(gè),你知道怎么解決呢?
回olay105:
先打開msvc\gtest.sln,編譯,生成Debug\gtestd.lib和Release\gtest.lib,這是庫文件。
把這個(gè)gtest.lib或gtestd.lib加入到這個(gè)“出現(xiàn)很多問題”的工程里。注意,因?yàn)閹煳募こ汤锬J(rèn)是“運(yùn)行時(shí)庫:多線程”,所以你的工程也要這么設(shè)置。
謝謝博主,我已經(jīng)解決問題了,很開心!
樓主:
我直接使用VC2005編譯的話也是有很多錯(cuò)誤,
錯(cuò)誤 13 未能刪除文件“c:\code\googletest\msvc\Release\vc80.idb”。
請(qǐng)確保該文件未被其他進(jìn)程打開并且未被寫保護(hù)。 gtest_output_test_
不知道是什么原因呢?我的環(huán)境里面還安裝了vc2003
謝謝。
樓主:
我直接使用VC2005編譯的話也是有很多錯(cuò)誤,
錯(cuò)誤 13 未能刪除文件“c:\code\googletest\msvc\Release\vc80.idb”。
請(qǐng)確保該文件未被其他進(jìn)程打開并且未被寫保護(hù)。 gtest_output_test_
不知道是什么原因呢?我的環(huán)境里面還安裝了vc2003
謝謝。