C++简易测试代码框架
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
????????在大多數(shù)情況下,我們寫了一個(gè)函數(shù),為了驗(yàn)證這個(gè)函數(shù)的正確性,我們還需要寫很多的測試代碼。可用于C/C++單元測試的框架有很多,什么cpptest, gtest等等不計(jì)其數(shù)。他們很強(qiáng)大,可以很方便的拿來使用到我們的項(xiàng)目中。但是有的時(shí)候,我的項(xiàng)目很小,或者說我的函數(shù)功能很少,小到運(yùn)行的時(shí)間比框架啟動的時(shí)間都還要短,這個(gè)時(shí)候我的目的很簡單,就是要以最簡單的形式,加入幾行代碼測試功能即可,如下:
TEST(func1()); TEST(func2()); ... TEST(func3());畢竟大多數(shù)程序員所在的公司都沒有或很少有專門的白盒測試人員,幾乎都要自己寫測試代碼。cpptest,gtest雖然也很簡單,但是還是要編譯,導(dǎo)入,并且會在系統(tǒng)中耗掉一部分時(shí)間。好比共享單車一樣,我就是想現(xiàn)在騎車出去耍一圈,我馬上,立刻就要騎,然而你要我花費(fèi)一點(diǎn)時(shí)間去借一輛自行車,這個(gè)時(shí)間我不愿意花,等我找到的時(shí)候或許我激情也沒有了。
????? ? 在我的項(xiàng)目中,有時(shí)候創(chuàng)建一個(gè)C++工程就僅僅是為了寫一個(gè)算法而已,這個(gè)時(shí)候如果能簡單到導(dǎo)入一個(gè)頭文件,加幾個(gè)宏定義,就能完成測試,那該多是多美好的事情。盡管寫很多 if (condition) then 這樣的語句很簡單,但打印出來的效果實(shí)在太難看,也很耗費(fèi)時(shí)間。在此基礎(chǔ)上,做了一個(gè)小型的測試代碼封裝,只需要包含兩個(gè)文件,寫幾行宏定義即可完成代碼測試。
.h頭文件:
#ifndef CPPTEST_H #define CPPTEST_H// This is a simple test-driver framework for C++ /** Example:** TEST_SUIT_BEGIN;** TEST_UNIT_BEGIN("function_test1");* TEST_CHECK(xpod_common::equal(10.0, 10-0.2, 0.1), "10.0, 10-0.2, 0.1");* TEST_CHECK(xpod_common::equal(10.0, 10-0.1, 0.1), "10.0, 10-0.1, 0.1");* TEST_CHECK(xpod_common::equal(10.0, 10-0.0, 0.1), "10.0, 10-0.0, 0.1");* TEST_UNIT_END;** TEST_UNIT_BEGIN("function_test2");* TEST_CHECK(xpod_common::equal(10.0, 10-0.2, 0.1), "10.0, 10-0.2, 0.1");* TEST_CHECK(xpod_common::equal(10.0, 10-0.1, 0.1), "10.0, 10-0.1, 0.1");* TEST_CHECK(xpod_common::equal(10.0, 10-0.0, 0.1), "10.0, 10-0.0, 0.1");* TEST_UNIT_END;** TEST_SUIT_END;* */#define TEST_SUIT_BEGIN TSuit::instance()->begin()#define TEST_SUIT_END TSuit::instance()->end();#define TEST_UNIT_BEGIN(name) \ { \TUnit unit(name); \unit.begin()#define TEST_CHECK(condition, msg) \unit.testCheck(condition, msg)#define TEST_UNIT_END \unit.end(); \TSuit::instance()->addNumAll(unit.numAll()); \TSuit::instance()->addNumOK(unit.numOK()); \TSuit::instance()->addUnit(); \ }#include <ctime> #include <string>using namespace std;class TUnit { public:TUnit(const char* name):_name(name){}unsigned int numOK(){return _numOK;}unsigned int numAll(){return _numAll;}void testCheck(bool bCheck, const char* msg);void begin();void end(); private:unsigned int _numOK = 0;unsigned int _numAll = 0;string _name; };class TSuit { public:static TSuit* instance(); public:void addNumAll(unsigned int count){_numAll+=count;}void addNumOK(unsigned int count){_numOK+=count;}void addUnit(){++_numUnit;}void begin();void end(); private:TSuit(){}clock_t _tstart;unsigned int _numOK = 0;unsigned int _numAll = 0;unsigned int _numUnit = 0; };#endif // CPPTEST_H.cpp源文件:
#include "cpptest.h" #include <windows.h>string date_time() {time_t rawtime;time(&rawtime);struct tm * timeinfo = localtime (&rawtime);char buffer[256] = {0};strftime(buffer, 256, "[%Y-%m-%d %H:%M:%S]", timeinfo);return string(buffer); }void printWarning(const char* msg) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), BACKGROUND_RED|BACKGROUND_GREEN);printf("%s\n", msg);SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); }void printError(const char* msg) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), BACKGROUND_RED);printf("%s\n", msg);SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); }void printResult(bool bOK) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), bOK?BACKGROUND_GREEN:BACKGROUND_RED);printf(bOK ? "[ OK ]" : "[ FAILED ]");SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);printf(" "); }void TUnit::testCheck(bool bCheck, const char* msg) {printResult(bCheck);printf("%s\n", (msg!=nullptr)?msg:" ");_numOK += bCheck ? 1 : 0;_numAll += 1; }void TUnit::begin() {printf("[ %s ]\n-----------------------------------------------------\n", _name.data()); }void TUnit::end() {printf("-----------------------------------------------------\nTotal:%d, Success:%d, Failed:%d\n\n", _numAll, _numOK, _numAll-_numOK); }TSuit *TSuit::instance() {static TSuit suit;return &suit; }void TSuit::begin() {_numOK = 0;_numAll = 0;_numUnit = 0;_tstart = clock();printf("Test Suit Begin %s\n-----------------------------------------------------\n\n", date_time().data()); }void TSuit::end() {printf("Test Suit End %s\n-----------------------------------------------------\n", date_time().data());printf("[Test Result] Unit:%d, Total:%d, Success:%d, Failed:%d, CostTime:%.2f s\n",_numUnit, _numAll, _numOK, _numAll-_numOK, (clock()-_tstart)/1000.0f); }兩個(gè)文件加起來不過150多行程序,僅定義一個(gè)單元測試TUnit和TSuit類,前者用來記錄一個(gè)單元測試的結(jié)果情況,后者用來記錄整體測試結(jié)果,在Windows控制臺支持彩色打印效果,還有執(zhí)行測試的全部時(shí)間。
下面為執(zhí)行測試的代碼:
void test_unit() { TEST_UNIT_BEGIN("123");TEST_CHECK(xpod_common::equal(10.0, 10-0.2, 0.15), "10.0, 10-0.2, 0.15");TEST_CHECK(xpod_common::equal(10.0, 10-0.1, 0.15), "10.0, 10-0.1, 0.15");TEST_CHECK(xpod_common::equal(10.0, 10-0.0, 0.15), "10.0, 10-0.0, 0.15");TEST_CHECK(xpod_common::equal(10.0, 10+0.1, 0.15), "10.0, 10+0.1, 0.15");TEST_CHECK(xpod_common::equal(10.0, 10+0.2, 0.15), "10.0, 10+0.2, 0.15"); TEST_UNIT_END; }int main(int argc, char *argv[]) {TEST_SUIT_BEGIN;test_unit();TEST_UNIT_BEGIN("equal");TEST_CHECK(xpod_common::equal(10.0, 10-0.2, 0.1), "10.0, 10-0.2, 0.1");TEST_CHECK(xpod_common::equal(10.0, 10-0.1, 0.1), "10.0, 10-0.1, 0.1");TEST_CHECK(xpod_common::equal(10.0, 10-0.0, 0.1), "10.0, 10-0.0, 0.1");TEST_CHECK(xpod_common::equal(10.0, 10+0.1, 0.1), "10.0, 10+0.1, 0.1");TEST_CHECK(xpod_common::equal(10.0, 10+0.2, 0.1), "10.0, 10+0.2, 0.1");TEST_UNIT_END;TEST_UNIT_BEGIN("equal");for (auto i=0; i<20; i++) {char buffer[128] = {0};sprintf(buffer, "10.0, 9+0.1*%d, 0.1", i);TEST_CHECK(xpod_common::equal(10.0, 9+0.1*i, 0.1), buffer);}TEST_UNIT_END;TEST_SUIT_END;return 0; }????????使用非常簡單,當(dāng)然功能也很簡單,無法和cpptest,gtest這樣的大型測試框架相媲美,但用到我的算法測試項(xiàng)目中正合適。后續(xù)有時(shí)間將增加UNIX版本的打印接口,如果能有邊界測試宏那就更好了,測試算法輸入接口不用再寫for語句了。
????? ? 最后來看看其中的一個(gè)測試效果:
? ? ? ??
轉(zhuǎn)載于:https://my.oschina.net/u/3489228/blog/968157
總結(jié)
以上是生活随笔為你收集整理的C++简易测试代码框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑直播需要什么设备
- 下一篇: 公布自己的pods到CocoaPods