文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>一个不足百行的单元测试框架:LazyTest

一个不足百行的单元测试框架:LazyTest

时间:2011-01-08  来源:lzprgmr

其实我只需要一个很简单的框架,只是针对一个算法实现,或者一个工具类写测试,而不是项目级别的。比如我写了一个max函数求两个数中较大的那个,那么测试代码可以这么写:

TESTCASE(test_max_int)
{
    ASSERT_TRUE(max(1, 10) == 10);
    ASSERT_TRUE(max(100, 10) == 100);
    ASSERT_TRUE(max(10, 10) == 10);

     return true;
}

TESTCASE(test_max_float)
{
    ASSERT_TRUE(max(1.1, 10.1) == 10.1);
    ASSERT_TRUE(max(100.1, 10.1) == 100.1);
    ASSERT_TRUE(max(10.1, 10.1) == 10.1);

     return true;
}

 

然后RUN_ALL_CASES就可以了。

仔细想了一下,这个也不难实现,主要考虑这么几个方面:

  • test case的自动注册
    这个可以在声明TESTCASE时用一个全局静态变量的构造函数实现
  • test case的管理与运行
    只要将所有的case注册到一个容器中,最后遍历该容器调用case即可
  • 宣告case失败并提高错误信息
    用一个宏来检查某个表达式,若失败则做两件事:一是output错误行与表达式;二是返回false宣告case失败.
下面就是实现,你也可以下载该文件:http://code.google.com/p/baiyanhuang/source/browse/trunk/LazyLib/LazyTest.h
//
// Description:
// A simple unit-test framework which aims to testing simple programs like utility class, algorithm...
// 
// How to use:
// You only need to know 3 macros to use this framework: TESTCASE, ASSERT_TRUE, RUN_ALL_CASES
// TESTCASE(testname)
// {
//     ASSERT_TRUE(1 + 1 ==  2);
//     return true;
// }
// ...
// RUN_ALL_CASES();
//
// Author: lzprgmr
// Date: 1/8/2011
//

#pragma once

#include <map>
#include <iostream>

#if defined(_WIN32)
#include <Windows.h>
#endif

#if !defined(LazyTestOut)
#define LazyTestOut std::cout
#endif

// typedefs
typedef unsigned int uint32_t;
typedef bool (*TestFunc) ();
typedef std::map<char*, TestFunc> TestCaseMap;

// Manage and run all test cases
class TestMgr
{
public:
        static TestMgr* Get()
        {
                static TestMgr _instance;
                return &_instance;
        }

        void AddTest(char* tcName, TestFunc tcFunc)
        {
                m_tcList[tcName] = tcFunc;
        }
        
        uint32_t RunAllCases()
        {
                uint32_t failure = 0;
                for(TestCaseMap::iterator it = m_tcList.begin(); it != m_tcList.end(); ++it)
                {
                        LazyTestOut << "Running " << it->first << "... " << std::endl;
                        bool bRes = RunCase(it->second);
                        if(bRes) LazyTestOut << "\tPass" << std::endl;
            else failure++;
                }
                LazyTestOut << "\n" << "Totally "<< failure << " cases failed!!!" << std::endl;
                return failure;
        }

private:
        bool RunCase(TestFunc tf)
        {
                bool bRes = false;
#if defined(_WIN32)
        // Windows use SEH to handle machine exceptions
                __try
                {
                        bRes = tf();
                }
                __except(EXCEPTION_EXECUTE_HANDLER)
                {
                        LazyTestOut << "\tException caught!" << std::endl;
                        bRes = false;
                }
#else 
        //Non-Windows OS that doesn't support SEH - the singal mechanism (SIGSEGV) can't work well as SEH to handle the problem
        bRes = tf();
#endif

                return bRes;
        }

private:
        TestCaseMap m_tcList;
};

// Register a test case
class TestCaseRegister
{
public:
        TestCaseRegister(char* tcName, TestFunc tcFunc) { TestMgr::Get()->AddTest(tcName, tcFunc); }
};


// To use this test framework, you only need to know 3 macros:
#define TESTCASE(tc)                                                                    \
        bool tc();                                                                          \
        TestCaseRegister register_##tc(#tc, tc);                                            \
        bool tc()

#define ASSERT_TRUE(expr) do {if(!(expr)) {                                             \
    LazyTestOut << "\tFailed at: " << __FILE__ << ": Line " <<__LINE__ << std::endl;    \
    LazyTestOut << "\tExpression: " << #expr << std::endl;                              \
    return false;}} while(false)

#define RUN_ALL_CASES()  do {TestMgr::Get()->RunAllCases(); } while(false)

 

如果我运行以下代码:

TESTCASE(test1)
{
    ASSERT_TRUE(1 + 1 ==  2);
    return true;
}

TESTCASE(test2)
{
    ASSERT_TRUE(1 + 1 !=  2);
    return true;
}

TESTCASE(test3)
{
    int* p = NULL;
    *p = 10;
    ASSERT_TRUE(1 + 1 ==  2);

    return true;
}

int main()
{
    RUN_ALL_CASES();
    return 0;
}

 

输出结果如下:

Running test1...
        Pass
Running test2...
        Failed at: c:\source\baiyanhuang\algorithm\test.cpp: Line 12
        Expression: 1 + 1 != 2
Running test3...
        Exception caught!
Totally 2 cases failed!!!

 

这里需要注意的几点是:

  • 该代码可以在mac和windows下运行,linux下没试过,应该也可以。但是只有在Windows下用SEH对内存访问错误等硬件错误进行了处理,Mac下singal机制对SIGSEGV的处理不能像SEH那样很好的解决这个问题。
  • 写case的时候,case名字不能重复(废话?),并且必须在每个case最后返回true - 这个可能可以简化一下,还没想到怎么做~~~
  • 信息默认输出到std::out,你也可以在include该文件之前先define自己的LazyTestOut
相关阅读 更多 +
排行榜 更多 +
火柴人战争血腥打击

火柴人战争血腥打击

飞行射击 下载
三角符文第一章下载

三角符文第一章下载

角色扮演 下载
闪客快打3无敌版下载

闪客快打3无敌版下载

飞行射击 下载