玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架
一、前言
上一篇我們分析了gtest的一些內(nèi)部實現(xiàn),總的來說整體的流程并不復(fù)雜。本篇我們就嘗試編寫一個精簡版本的C++單元測試框架:nancytest ,通過編寫這個簡單的測試框架,將有助于我們理解gtest。
二、整體設(shè)計
使用最精簡的設(shè)計,我們就用兩個類,夠簡單吧:
1. TestCase類
包含單個測試案例的信息。?
2. UnitTest類
負(fù)責(zé)所有測試案例的執(zhí)行,管理。
三、TestCase類
TestCase類包含一個測試案例的基本信息,包括:測試案例名稱,測試案例執(zhí)行結(jié)果,同時還提供了測試案例執(zhí)行的方法。我們編寫的測試案例都繼承自TestCase類。
{
public:
????TestCase(const?char*?case_name)?:?testcase_name(case_name){}
????//?執(zhí)行測試案例的方法
????virtual?void?Run()?=?0;
????int?nTestResult;?//?測試案例的執(zhí)行結(jié)果?
????const?char*?testcase_name;?//?測試案例名稱
};
?
四、UnitTest類
我們的UnitTest類和gtest的一樣,是一個單件。我們的UnitTest類的邏輯非常簡單:
1. 整個進(jìn)程空間保存一個UnitTest 的單例。
2. 通過RegisterTestCase()將測試案例添加到測試案例集合testcases_中。
3. 執(zhí)行測試案例時,調(diào)用UnitTest::Run(),遍歷測試案例集合testcases_,調(diào)用案例的Run()方法
class?UnitTest{
public:
????//?獲取單例
????static?UnitTest*?GetInstance();?
????//?注冊測試案例
????TestCase*?RegisterTestCase(TestCase*?testcase);
????
????//?執(zhí)行單元測試
????int?Run();
????TestCase*?CurrentTestCase;?//?記錄當(dāng)前執(zhí)行的測試案例
????int?nTestResult;?//?總的執(zhí)行結(jié)果
????int?nPassed;?//?通過案例數(shù)
????int?nFailed;?//?失敗案例數(shù)
protected:
????std::vector<TestCase*>?testcases_;?//?案例集合
};
下面是UnitTest類的實現(xiàn):
UnitTest*?UnitTest::GetInstance(){
????static?UnitTest?instance;
????return?&instance;
}
TestCase*?UnitTest::RegisterTestCase(TestCase*?testcase)
{
????testcases_.push_back(testcase);
????return?testcase;
}
int?UnitTest::Run()
{
????nTestResult?=?1;
????for?(std::vector<TestCase*>::iterator?it?=?testcases_.begin();
????????it?!=?testcases_.end();?++it)
????{
????????TestCase*?testcase?=?*it;
????????CurrentTestCase?=?testcase;
????????std::cout?<<?green?<<?"======================================"?<<?std::endl;
????????std::cout?<<?green?<<?"Run?TestCase:"?<<?testcase->testcase_name?<<?std::endl;
????????testcase->Run();
????????std::cout?<<?green?<<?"End?TestCase:"?<<?testcase->testcase_name?<<?std::endl;
????????if?(testcase->nTestResult)
????????{
????????????nPassed++;
????????}
????????else
????????{
????????????nFailed++;
????????????nTestResult?=?0;
????????}
????}
????std::cout?<<?green?<<?"======================================"?<<?std::endl;
????std::cout?<<?green?<<?"Total?TestCase?:?"?<<?nPassed?+?nFailed?<<?std::endl;
????std::cout?<<?green?<<?"Passed?:?"?<<?nPassed?<<?std::endl;
????std::cout?<<?red?<<?"Failed?:?"?<<?nFailed?<<?std::endl;
????return?nTestResult;
}
五、NTEST宏
接下來定一個宏NTEST,方便我們寫我們的測試案例的類。
????testcase_name##_TEST
#define?NANCY_TEST_(testcase_name)?\
class?TESTCASE_NAME(testcase_name)?:?public?TestCase?\
{?\
public:?\
????TESTCASE_NAME(testcase_name)(const?char*?case_name)?:?TestCase(case_name){};?\
????virtual?void?Run();?\
private:?\
????static?TestCase*?const?testcase_;?\
};?\
\
TestCase*?const?TESTCASE_NAME(testcase_name)?\
????::testcase_?=?UnitTest::GetInstance()->RegisterTestCase(?\
????????new?TESTCASE_NAME(testcase_name)(#testcase_name));?\
void?TESTCASE_NAME(testcase_name)::Run()
#define?NTEST(testcase_name)?\
????NANCY_TEST_(testcase_name)
?
六、RUN_ALL_TEST宏
然后是執(zhí)行所有測試案例的一個宏:
#define?RUN_ALL_TESTS()?\????UnitTest::GetInstance()->Run();
七、斷言的宏EXPECT_EQ?
這里,我只寫一個簡單的EXPECT_EQ :
????if?(m?!=?n)?\
????{?\
????????UnitTest::GetInstance()->CurrentTestCase->nTestResult?=?0;?\
????????std::cout?<<?red?<<?"Failed"?<<?std::endl;?\
????????std::cout?<<?red?<<?"Expect:"?<<?m?<<?std::endl;?\
????????std::cout?<<?red?<<?"Actual:"?<<?n?<<?std::endl;?\
????}
?
八、案例Demo
夠簡單吧,再來看看案例怎么寫:
#include?"nancytest.h"
int?Foo(int?a,?int?b)
{
????return?a?+?b;
}
NTEST(FooTest_PassDemo)
{
????EXPECT_EQ(3,?Foo(1,?2));
????EXPECT_EQ(2,?Foo(1,?1));
}
NTEST(FooTest_FailDemo)
{
????EXPECT_EQ(4,?Foo(1,?2));
????EXPECT_EQ(2,?Foo(1,?2));
}
int?_tmain(int?argc,?_TCHAR*?argv[])
{
????return?RUN_ALL_TESTS();
}
整個一山寨版gtest,呵。執(zhí)行一下,看看結(jié)果怎么樣:
?
九、總結(jié)?
本篇介紹性的文字比較少,主要是我們在上一篇深入解析gtest時已經(jīng)將整個流程弄清楚了,而現(xiàn)在編寫的nancytest又是其非常的精簡版本,所有直接看代碼就可以完全理解。希望通過這個Demo,能夠讓大家對gtest有更加直觀的了解。回到開篇時所說的,我們沒有必要每個人都造一個輪子,因為gtest已經(jīng)非常出色的為我們做好了這一切。如果我們每個人都寫一個自己的框架的話,一方面我們要付出大量的維護(hù)成本,一方面,這個框架也許只能對你有用,無法讓大家從中受益。
gtest正是這么一個優(yōu)秀C++單元測試框架,它完全開源,允許我們一起為其貢獻(xiàn)力量,并能讓更多人從中受益。如果你在使用gtest過程中發(fā)現(xiàn)gtest不能滿足你的需求時(或發(fā)現(xiàn)BUG),gtest的開發(fā)人員非常急切的想知道他們哪來沒做好,或者是gtest其實有這個功能,但是很多用戶都不知道。所以你可以直接聯(lián)系gtest的開發(fā)人員,或者你直接在這里回帖,我會將您的意見轉(zhuǎn)告給gtest的主要開發(fā)人員。
如果你是gtest的超級粉絲,原意為gtest貢獻(xiàn)代碼的話,加入他們吧。
本Demo代碼下載:/Files/coderzh/Code/nancytest.rar?
本篇是該系列最后一篇,其實gtest還有更多東西值得我們?nèi)ヌ剿?#xff0c;本系列也不可能將gtest介紹完全,還是那句話,想了解更多gtest相關(guān)的內(nèi)容的話:
訪問官方主頁:http://code.google.com/p/googletest/
下載gtest源碼:?http://code.google.com/p/googletest/downloads/list
總結(jié)
以上是生活随笔為你收集整理的玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 玩转Google开源C++单元测试框架G
- 下一篇: 反汇编程序导致程序crash的解决思路