C++簡易測試代碼框架

        在大多數狀況下,咱們寫了一個函數,爲了驗證這個函數的正確性,咱們還須要寫不少的測試代碼。可用於C/C++單元測試的框架有不少,什麼cpptest, gtest等等不可勝數。他們很強大,能夠很方便的拿來使用到咱們的項目中。可是有的時候,個人項目很小,或者說個人函數功能不多,小到運行的時間比框架啓動的時間都還要短,這個時候個人目的很簡單,就是要以最簡單的形式,加入幾行代碼測試功能便可,以下:程序員

TEST(func1());
TEST(func2());
...
TEST(func3());

畢竟大多數程序員所在的公司都沒有或不多有專門的白盒測試人員,幾乎都要本身寫測試代碼。cpptest,gtest雖然也很簡單,可是仍是要編譯,導入,而且會在系統中耗掉一部分時間。比如共享單車同樣,我就是想如今騎車出去耍一圈,我立刻,馬上就要騎,然而你要我花費一點時間去借一輛自行車,這個時間我不肯意花,等我找到的時候或許我激情也沒有了。算法

        在個人項目中,有時候建立一個C++工程就僅僅是爲了寫一個算法而已,這個時候若是能簡單到導入一個頭文件,加幾個宏定義,就能完成測試,那該可能是多美好的事情。儘管寫不少 if (condition) then 這樣的語句很簡單,但打印出來的效果實在太難看,也很耗費時間。在此基礎上,作了一個小型的測試代碼封裝,只須要包含兩個文件,寫幾行宏定義便可完成代碼測試。windows

.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);
}

兩個文件加起來不過150多行程序,僅定義一個單元測試TUnit和TSuit類,前者用來記錄一個單元測試的結果狀況,後者用來記錄總體測試結果,在Windows控制檯支持彩色打印效果,還有執行測試的所有時間。單元測試

下面爲執行測試的代碼:測試

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;
}

        使用很是簡單,固然功能也很簡單,沒法和cpptest,gtest這樣的大型測試框架相媲美,但用到個人算法測試項目中正合適。後續有時間將增長UNIX版本的打印接口,若是能有邊界測試宏那就更好了,測試算法輸入接口不用再寫for語句了。ui

        最後來看看其中的一個測試效果:spa

        

相關文章
相關標籤/搜索