逖靖寒的世界

每天进步一点点

导航

短小精悍的C++单元测试框架CppUnitLite源码分析

这几天集中精力阅读2个C++的测试框架源代码,一个是CppUnit,另一个就是今天要说的CppUnitLite啦。

CppUnitLite是一个由Michael Feathers开发的短小精悍的C++测试框架,Michael Feathers同时也是CppUnit的原作者。使用者可以通过这个框架根据自己的实际需要进行扩展。

  1. http://www.objectmentor.com/resources/downloads.html
  2. http://www.objectmentor.com/resources/bin/CppUnitLite.zip

这个框架的目的在于:

  1. 为开发者提供容易编写的独立的测试。
  2. 遵循JavaUnit的模式,避免使用C++的一些高级特性,比如RTTI,异常,模板等,这些因素不利于程序的移植。

 

现在假设有一个Deque类需要测试,测试所用的代码如下:

#include "TestHarness.h"

#include "Deque.h"

//from http://www.cnblogs.com/gpcuster

int main()

{

    TestResult tr;

    TestRegistry::runAllTests(tr);

    return 0;

}

TEST( Deque, construction)

{

    Deque d;

    CHECK ( 0 == d.size() );

}

TEST (Deque, dont_try_suicide)

{

    Deque d;

    d.push_front(1);

    d = d;

    CHECK( 1 == d.pop_front());

}

tr是用来保存测试的结果的,你可以通过继承TestResult来添加自己需要,比如显示成功的测试有多少,失败的测试有多少。

TestRegistry::runAllTests(tr);这段代码表示开始执行测试。朋友们一定就会问啦,需要测试的代码是怎么关联进去的?要回答这个问题,我们可以看看实际要测试的代码,比如

TEST( Deque, construction)

{

    Deque d;

    CHECK ( 0 == d.size() );

}

这个函数看起来很奇怪,其实TEST是一个宏定义,这个框架中定义啦一个Test的基类,作者使用啦一个非常巧妙的宏(TEST)来生成一个派生与Test的类型,类型的名称由这个看似函数而不是函数的第一个参数(Deque)和第二个参数(construction)组成。同时实现啦Test::run函数,这里的实现也就是

{

    Deque d;

    CHECK ( 0 == d.size() );

}

其中的CHECK ( 0 == d.size() );也是用宏实现的。

为了能让大家看得更清楚,我们看看

TEST( Deque, construction)

{

    Deque d;

    CHECK ( 0 == d.size() );

}

这段代码在编译的时候变成了这个样子:

class constructionDequeTest : public Test

{

public:

    constructionDequeTest () : Test ("Deque" "Test") {} \

void run (TestResult& result_);

}constructionDequeInstance;

 

void constructionDequeTest::run (TestResult& result_)

{

    Deque d;

 

    //CHECK ( 0 == d.size() );

    {

        if (!(0 == d.size()))

        {

            result_.addFailure (Failure (name_, __FILE__,__LINE__, "0 == d.size()"));

            return;

        }

    }

}

这样,在编译的时候就自动生成啦一个用于测试类。

注意类定义的最后同时进行了实例化constructionDequeInstance,通过查看Test的代码你会发现,在实例话的时候调用了TestRegistry::addTest (this);这样,就把这个测试类的代码添加到了TestRegistry中去,同时TestRegistry又实现啦Singleton Pattern单件模式,所以我们也就很自然地回答了开始的问题(TestRegistry::runAllTests(tr);这段代码表示开始执行测试。朋友们一定就会问啦,需要测试的代码是怎么关联进去的?)。

如果大家有兴趣,可以进一步看一看Google公布的开源c++单元测试框架googletest

Google's framework for writing C++ tests on a variety of platforms (Linux, Mac OS X, Windows, Cygwin, Windows CE, and Symbian). Based on the xUnit architecture. Supports automatic test discovery, a rich set of assertions, user-defined assertions, death tests, fatal and non-fatal failures, value- and type-parameterized tests, various options for running the tests, and XML test report generation.

posted on 2009-02-08 09:56  逖靖寒  阅读(4015)  评论(6编辑  收藏  举报