CppUnit源码解读

CppUnit 的核心部分可分成三个主要部分,可以认为这三部分组成 MVC 模式。

 

 

1 Model

Test 类为基类,向下派生出 TestComposite, TestSuite, TestLeaf, TestCase 等。

其中 Test TestComposite TestLeaf 又构成一个 Composite 模式,由 TestCase 可以创建单个测试用例,而用 TestSuite 可以打包一组测试用例。 ( 个人认为 Test 类改为 TestComponent 可能更合适 )

 

test 类中,其主要虚函数为 virtual void run( TestResult *result ) =0; Controller 调用这个函数运行测试用例。

 

而在TestCase 中,添加了新的虚函数:virtual void runTest();run 函数实现如下:

void TestCase::run( TestResult *result )

{

  result->startTest(this);

  if ( result->protect( TestCaseMethodFunctor( this, &TestCase::setUp ), this, "setUp() failed" ) )

  {

    result->protect( TestCaseMethodFunctor( this, &TestCase::runTest ), this );

  }

  result->protect( TestCaseMethodFunctor( this, &TestCase::tearDown ), this, "tearDown() failed" );

 

  result->endTest( this );

}

可以看到,它在开始一个测试用例时,会回调 Controller StartTest 接口,而 Controller 再回调给 Listener ,最后由 Listener 进行一些操作 ( 比如将该 test 类插入自己的列表,或在界面上显示信息等 )

接着,调用 setUp 函数进行测试前的准备工作,比如准备资源,读取文件等。

setUp tearDown 接口由 TestFixture 定义。 TestCase 类从 TestFixture TestLeaf 多继承下来。

然后,调用 runTest ,运行测试。

测试结束后,调用 tearDown ,释放资源,调用 endTest ,通知 Controller

所以,如果我们从 TestCase 派生类写测试用例,应该改写 runTest 接口,而不应该动 run 接口。

 

TestSuite run 接口实现如下:

调用 Controller startSuite 进行通知;

对每一个子测试用例,调用run 接口

调用 Controller endSuite

 

 

 

2 Controller

主要就 TestResult 一个类( 个人认为应该改为TestController)

另外还有一些辅助的类,例如:

1)   TestFailure ExceptionMessageSourceLineAsserter 等一系列类支持用户在测试代码中加入断言,并且当测试用例失败时记录失败信息,代码位置等

 

 

2)   SynchronizedObject 及其内嵌的SynchronizationObjectExclusiveZone 支持多线程同步

3)   Protector ProtectorChainDefaultProtectorFunctorProtectFunctor 等类,使用了类似Decorator 的模式,在运行时组合Protector ,用于在测试用例失败时捕获异常,并根据异常类型生成相关失败/ 错误信息通知Controller

 

 

 

最后是 TestResult 类,它使用了Observer 模式,由多个Listener 注册监听Model 的运行状态。当测试用例开始,结束,有错误发生时,TestResult 调用每一个ListenerstartSuitestartTestaddFailure 等等接口回调通知Listener

 

3 View ,也就是 Listener

TestListener 是所有监听者的基类,定义了所有对测试过程和结果回调的接口。包括:

startTestRun/endTestRun :一个大的测试项目开始/ 结束

startSuite/endSuite :一个测试组合(TestSuite) 开始/ 结束

startTest/endTest :一个测试项目(TestCase) 开始/ 结束

addFailure :测试失败,有错误发生

 

4 TestRunner

TestRunner 相当于Fa ç ade 模式,在最高层提供接口使得底层的模型更易使用。

它主要有两个接口:

virtual void addTest( Test *test );

virtual void run( TestResult &controller, const std::string &testPath = "" );

 

CppUnit 预先为我们定义好了两个TestRunner ,基于控制台的TextTestRunner 和基于对话框的MfcTestRunner

 

 

---------------------------------------------------------------------------------------------------------------------

基于对CppUnit 框架的理解,我们很容易开发出单元测试项目。

例如,我们要测试CMyParser 类中的Parse(const CString &text) 接口,首先创建一个文件,存储我们的测试参数:

CMyParser_Parse_testcase.txt:

Line1

Line2

 

然后从TestCase 派生出单元测试类

class CMyParserTestCase : public CppUnit::TestCase

{

public:

     static void LoadTestCaseFromFile (const CString fileName, CStringList &caselist);

 

public:

     CMyParserTestCase(const CString &row);

     virtual ~CMyParserTestCase(void);

 

     void runTest();

 

private:

     CString m_row;

};

 

我们提供了一个静态函数LoadTestCaseFromFile 用于读取文件,载入测试参数。

实现如下:

CMyParserTestCase::CMyParserTestCase(const CString &row) : m_row(row){}

CMyParserTestCase::~CMyParserTestCase(void){}

void CMyParserTestCase::runTest()

{

     CMyParser myParser;

     CPPUNIT_ASSERT(myParser.Parse(m_row));

}

void CMyParserTestCase::LoadTestCaseFromFile (const CString fileName, CStringList &caselist)

{

  caselist.RemoveAll();

 

     CStdioFile file (fileName, CFile::modeRead);

     CString line;

     while (file.ReadString (line))

     {

         caselist.AddTail (line);

     }

}

runTest 中先创建CMyParser 实例,然后通过CPPUNIT_ASSERT 断言对Parse 接口测试。

 

我们的测试用例类实现了,接下来是主函数:

void main()

{

     TextUi::TestRunner runner;

     TestSuite *pSuite = new TestSuite;

 

     {// 加入测试子类

         CStringList caselist;

         CMyParserTestCase::LoadTestCaseFromFile ("CMyParser_Parse_testcase.txt", caselist);

 

         POSITION pos = caselist.GetHeadPosition();

         while(pos != NULL)

         {

              CString oneCase = caselist.GetNext (pos);

              CMyParserTestCase *pCase = new CMyParserTestCase (oneCase);

              pSuite->addTest (pCase);

         }

     }

    

     runner.addTest (pSuite);

     runner.run("", true, true, false);

}

整个过程是先创建基于控制台的TestRunner 实例,然后创建一个TestSuite ,往里面加入一系列的测试用例。最后调用TestRunneraddTestrun 接口。有了CppUnit 的框架,一切就这么简单。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值