snail源代碼分析, 提取了一個c++的單元測試框架

c++的單元測試框架有很多中了, 據說bcb2007裏面就包含了一個單元測試框架, 不過沒怎麼用過.
其他的不甚了了.

snail的源代碼中, 包含了一個c++的unittest框架,  差不多可以叫做SLUnit .

可以閱讀其源代碼, 其實寫得東西很少. 其基本思想我們在這裏描述一下.

呵呵, 聽說junit是作者在坐飛機的時候寫出來的, 可想而知, 單元測試, 在於思想, 不在於表現. 理解的人, 可以一下悟到, 不理解的, 也可以先用着工具, 將來也能一下豁然開朗.

junit和nunit都是基於反射來實現單元測試的. 所以, 只需要寫一些metadata或者對方法的名字有所規定, 就能實現一個testcase, 由framework來執行這些testcase.

c++在metadata, rtti方面的支持比較弱. 所以企圖靠metadata, 方法命名來做這件事情的嘗試, 肯定是行不通了.
不過, 思想還是一樣的. metadata, 從本質而言, 是一些額外的類型,等信息, 還有一些是編譯器生成的, 還有一些是認爲自定義的. 既然是一些額外的信息, 那麼我們在做cpp的單元測試框架的時候, 需要手工添加一些額外信息就可以了.

此外c++裏面有宏可以利用,  可以減少一些書寫這些metadata的書寫工作.

還有一個功能就是: 出錯, 報告之後, 定位. 報告哪裏出的錯誤. 這個需要用到__LINE__, __FILE__等信息了..

好了閒話少說. 帖一段代碼, 呵呵很簡單東西也很少.:










#ifndef __SUNIT_HPP__
#define __SUNIT_HPP__

/*
**  simple unit test framework for c++
**  author: bianpeng
**  date: 2008-01-31
**  license: apache 2.0
*/

#include <vector>
#include <string>
#include <iostream>

namespace sunit {
    
    class SUnitFrameWork;

    /// use for non pointer compare
    template<class T>
    bool _CheckEquals(const T & a, const T & b) {
        return a == b;
    }

    /// use for pointer compare
    template<class T>
    bool _CheckEquals(T * a, T * b) {
        return *a == *b;
    }

#define AssertEqual(a, b)           /
    _AssertEqual(a, b, __FILE__, __LINE__);

#define __CHECK_EQUAL__(a, b)           /
    do {                               /
        if (!_CheckEquals(a, b)) {        /
            char strBuf[50];strBuf[49]=0;sprintf_s(strBuf, 49, "%d", line);              /
            SUnitFrameWork::Instance()->Console()->Write(file);         /
            SUnitFrameWork::Instance()->Console()->Write(": ");          /
            SUnitFrameWork::Instance()->Console()->WriteLn(strBuf);     /
        }                               /
    } while(0);    

    template<class T>
    void _AssertEqual(const T & a, const T & b, const char * file, const int line) {
        __CHECK_EQUAL__(a, b);
    }

    template<class T>
    void _AssertEqual(T * a, T * b, const char * file, const int line) {
        __CHECK_EQUAL__(a, b);
    }

    // 保證肯定有一個實例化的測試用例,
    template<class T>
    class SingletonTestCase {
        protected:
            static T * _instance;
    };

    template<class T>
    T * SingletonTestCase<T>::_instance = new T;


    class SUnitTestCase {
        public:
            SUnitTestCase();
            ~SUnitTestCase();
        public:
            virtual void SetUp() {}
            virtual void Run() {}
            virtual void TearDown() {}
    };

    class SUnitConsole {
        public:
            virtual void WriteLn(const std::string & msg) = 0;
            virtual void Write(const std::string & msg) = 0;
    };

    class SUnitFrameWork {
        private:
            std::vector<SUnitTestCase*> _testCases;
            static SUnitFrameWork * _instance;
            SUnitConsole * _console;
        public:
            void RunConsole();
            void RunGUI();
        public:
            static SUnitFrameWork * Instance() {
                if (!_instance) {
                    _instance = new SUnitFrameWork();
                }
                return _instance;
            }
            void Add(SUnitTestCase * test) {
                _testCases.push_back(test);
            }

            SUnitConsole * Console() {
                return _console;
            }
    };
};

/// some usefull testcase implementation...

#define CLASS_DEF(name)                     /
    class SUnitTestcase_##name :           /
    public sunit::SUnitTestCase,           /
        public SingletonTestCase<SUnitTestcase_##name> {  /
    private:                               /
        void Dummy() { (void)_instance;}  /
    public:                                    

#define CLASS_END                           /
    };

#define METHOD_IMPL(_ClassName, _MethodName)        /
    SUnitTestcase_##_ClassName::_MethodName


#endif //__SUNIT_HPP__

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章