﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Just enjoy programming-随笔分类-软件工程</title><link>http://www.cppblog.com/tankzhouqiang/category/18742.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2012 13:10:08 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2012 13:10:08 GMT</pubDate><ttl>60</ttl><item><title>CppUnit快速入门（转载）</title><link>http://www.cppblog.com/tankzhouqiang/archive/2012/03/01/166911.html</link><dc:creator>周强</dc:creator><author>周强</author><pubDate>Thu, 01 Mar 2012 12:25:00 GMT</pubDate><guid>http://www.cppblog.com/tankzhouqiang/archive/2012/03/01/166911.html</guid><wfw:comment>http://www.cppblog.com/tankzhouqiang/comments/166911.html</wfw:comment><comments>http://www.cppblog.com/tankzhouqiang/archive/2012/03/01/166911.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tankzhouqiang/comments/commentRss/166911.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tankzhouqiang/services/trackbacks/166911.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">简介</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">测试是软件开发过程中极其重要的一环，详尽周密的测试能够减少软件BUG，提高软件品质。测试包括单元测试、系统测试等。其中单元测试是指针对软件功能单元所作的测试，这里的功能单元可以是一个类的属性或者方法，测试的目的是看这些基本单元是否工作正常。由于单元测试的内容很基础，因此可以看作是测试工作的第一环，该项工作一般由开发人员自行完成。如果条件允许，单元测试代码的开发应与程序代码的开发同步进行。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">虽然不同程序的单元测试代码不尽相同，但测试代码的框架却非常相似，于是便出现了一些单元测试类库，CppUnit便是其中之一。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">CppUnit是XUnit中的一员，XUnit是一个大家族，还包括JUnit和PythonUnit等。CppUnit简单实用，学习和使用起来都很方便，网上已有一些文章对其作介绍，但本文更着重于讲解其中的基本概念和使用方法，以帮助初次接触CppUnit的人员快速入门。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">安装</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">目前，CppUnit的最新版本是1.10.2，你可以从下面地址获取：</p><a href="http://sourceforge.net/projects/cppunit/" style="color: #336699; text-decoration: none; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">http://sourceforge.net/projects/cppunit</a><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">解压后，你可以看到CppUnit包含如下目录：</p><pre style="word-wrap: break-word; white-space: normal; line-height: 26px; text-align: left; background-color: #f5f5f5; color: green; ">config： 配置文件 contrib： contribution，其他人贡献的外围代码 doc： 文档，需要通过doxygen工具生成，也可以直接从sourceforge站点上下载打包好的文档 examples：示例代码 include： 头文件 lib： 存放编译好的库 src： 源文件，以及编译库的工程等</pre><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">然后打开src目录下的CppUnitLibraries工程，执行build/batch build，编译成功的话，生成的库文件将被拷贝到lib目录下。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">你也可以根据需要选择所需的项目进行编译，其中项目cppunit为静态库，cppunit_dll为动态库，生成的库文件为：</p><pre style="word-wrap: break-word; white-space: normal; line-height: 26px; text-align: left; background-color: #f5f5f5; color: green; ">cppunit.lib： 静态库release版 cppunitd.lib： 静态库debug版 cppunit_dll.lib： 动态库release版 cppunitd_dll.lib：动态库debug版</pre><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">要使用CppUnit，还得设置好头文件和库文件路径，以VC6为例，选择Tools/Options/Directories，在Include files和Library files中分别添加%CppUnitPath%/include和%CppUnitPath%/lib，其中%CppUnitPath%表示CppUnit所在路径。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">做好准备工作后，我们就可以编写自己的单元测试代码了。需说明的是，CppUnit所用的动态运行期库均为多线程动态库，因此你的单元测试程序也得使用相应设置，否则会发生冲突。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">概念</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在使用之前，我们有必要认识一下CppUnit中的主要类，当然你也可以先看后面的例子，遇到问题再回过头来看这一节。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">CppUnit核心内容主要包括六个方面，</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">1. 测试对象（Test，TestFixture，...）：用于开发测试用例，以及对测试用例进行组织管理。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">2. 测试结果（TestResult）：处理测试用例执行结果。TestResult与下面的TestListener采用的是观察者模式（Observer Pattern）。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">3. 测试结果监听者（TestListener）：TestListener作为TestResult的观察者，担任实际的结果处理角色。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">4. 结果输出（Outputter）：将结果进行输出，可以制定不同的输出格式。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">5. 对象工厂（TestFactory）：用于创建测试对象，对测试用例进行自动化管理。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">6. 测试执行体（TestRunner）：用于运行一个测试。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">以上各模块的主要类继承结构如下：</p><pre style="word-wrap: break-word; white-space: normal; line-height: 26px; text-align: left; background-color: #f5f5f5; color: green; ">Test TestFixture TestResult TestListener _______|_________ | | | | | TestSuccessListener TestComposite TestLeaf | | | |____________| TestResultCollector TestSuit | TestCase | TestCaller&lt;Fixture&gt; Outputter TestFactory TestRunner ____________________|_________________ | | | | TestFactoryRegistry CompilerOutputter TextOutputter XmlOutputter | TestSuiteFactory&lt;TestCaseType&gt;</pre><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">接下来再对其中一些关键类作以介绍。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">Test：所有测试对象的基类。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">CppUnit采用树形结构来组织管理测试对象（类似于目录树），因此这里采用了组合设计模式（Composite Pattern），Test的两个直接子类TestLeaf和TestComposite分别表示&#8220;测试树&#8221;中的叶节点和非叶节点，其中TestComposite主要起组织管理的作用，就像目录树中的文件夹，而TestLeaf才是最终具有执行能力的测试对象，就像目录树中的文件。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">Test最重要的一个公共接口为：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">virtual void run(TestResult *result) = 0;</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">其作用为执行测试对象，将结果提交给result。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在实际应用中，我们一般不会直接使用Test、TestComposite以及TestLeaf，除非我们要重新定制某些机制。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestFixture：用于维护一组测试用例的上下文环境。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在实际应用中，我们经常会开发一组测试用例来对某个类的接口加以测试，而这些测试用例很可能具有相同的初始化和清理代码。为此，CppUnit引入TestFixture来实现这一机制。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestFixture具有以下两个接口，分别用于处理测试环境的初始化与清理工作：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">virtual void setUp();&nbsp;<br />virtual void tearDown();&nbsp;</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestCase：测试用例，从名字上就可以看出来，它便是单元测试的执行对象。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestCase从Test和TestFixture多继承而来，通过把Test::run制定成模板函数（Template Method）而将两个父类的操作融合在一起，run函数的伪定义如下：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">// 伪代码&nbsp;<br />void&nbsp;TestCase::run(TestResult*&nbsp;result)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;result-&gt;startTest(this);&nbsp;//&nbsp;通知result测试开始<br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;result-&gt;protect(this,&nbsp;&amp;TestCase::setUp)&nbsp;)&nbsp;//&nbsp;调用setUp，初始化环境<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result-&gt;protect(this,&nbsp;&amp;TestCase::runTest);&nbsp;//&nbsp;执行runTest，即真正的测试代码<br />&nbsp;&nbsp;&nbsp;&nbsp;result-&gt;protect(this,&nbsp;&amp;TestCase::tearDown);&nbsp;//&nbsp;调用tearDown，清理环境<br />&nbsp;&nbsp;&nbsp;&nbsp;result-&gt;endTest(this);&nbsp;//&nbsp;通知result测试结束<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这里要提到的是函数runTest，它是TestCase定义的一个接口，原型如下：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">virtual void runTest();</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">用户需从TestCase派生出子类并实现runTest以开发自己所需的测试用例。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">另外还要提到的就是TestResult的protect方法，其作用是对执行函数（实际上是函数对象）的错误信息（包括断言和异常等）进行捕获，从而实现对测试结果的统计。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestSuit：测试包，按照树形结构管理测试用例</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestSuit是TestComposite的一个实现，它采用vector来管理子测试对象（Test），从而形成递归的树形结构。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestCaller：TestCase适配器（Adapter），它将成员函数转换成测试用例</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">虽然我们可以从TestCase派生自己的测试类，但从TestCase类的定义可以看出，它只能支持一个测试用例，这对于测试代码的组织和维护很不方便，尤其是那些有共同上下文环境的一组测试。为此，CppUnit提供了TestCaller以解决这个问题。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestCaller是一个模板类，它以实现了TestFixture接口的类为模板参数，将目标类中某个符合runTest原型的测试方法适配成TestCase的子类。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">在实际应用中，我们大多采用TestFixture和TestCaller相组合的方式，具体例子参见后文。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestResult和TestListener：处理测试信息和结果</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">前面已经提到，TestResult和TestListener采用了观察者模式，TestResult维护一个注册表，用于管理向其登记过的TestListener，当TestResult收到测试对象（Test）的测试信息时，再一一分发给它所管辖的TestListener。这一设计有助于实现对同一测试的多种处理方式。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestFactory：测试工厂</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这是一个辅助类，通过借助一系列宏定义让测试用例的组织管理变得自动化。参见后面的例子。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestRunner：用于执行测试用例</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">TestRunner将待执行的测试对象管理起来，然后供用户调用。其接口为：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">virtual void addTest( Test *test ); virtual void run( TestResult &amp;controller, const std::string &amp;testPath = "" );</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">这也是一个辅助类，需注意的是，通过addTest添加到TestRunner中的测试对象必须是通过new动态创建的，用户不能删除这个对象，因为TestRunner将自行管理测试对象的生命期。</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">使用</p><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">先让我们看看一个简单的例子：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">#include&nbsp;&lt;cppunit/TestCase.h&gt;<br />#include&nbsp;&lt;cppunit/TestResult.h&gt;<br />#include&nbsp;&lt;cppunit/TestResultCollector.h&gt;<br />#include&nbsp;&lt;cppunit/TextOutputter.h&gt;<br /><br />//&nbsp;定义测试用例<br />class&nbsp;SimpleTest&nbsp;:&nbsp;public&nbsp;CppUnit::TestCase<br />{<br />public:<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;runTest()&nbsp;//&nbsp;重载测试方法<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT_EQUAL(0, i);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />};<br /><br />int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResult&nbsp;r;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResultCollector&nbsp;rc;<br />&nbsp;&nbsp;&nbsp;&nbsp;r.addListener(&amp;rc);&nbsp;//&nbsp;准备好结果收集器&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;SimpleTest&nbsp;t;<br />&nbsp;&nbsp;&nbsp;&nbsp;t.run(&amp;r);&nbsp;//&nbsp;运行测试用例<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TextOutputter&nbsp;o(&amp;rc,&nbsp;std::cout);<br />&nbsp;&nbsp;&nbsp;&nbsp;o.write();&nbsp;//&nbsp;将结果输出<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />}</div><span style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">编译后运行，输出结果为：</span><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">!!!FAILURES!!!<br />Test Results:<br />Run: 1 Failures: 1 Errors: 0<br /><br />1) test: (F) line: 18 E:/CppUnitExamples/SimpleTest.cpp<br />equality assertion failed<br />- Expected: 1<br />- Actual : 0</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">上面的例子很简单，需说明的是CPPUNIT_ASSERT_EQUAL宏。CppUnit定义了一组宏用于检测错误，CPPUNIT_ASSERT_EQUAL是其中之一，当断言失败时，CppUnit便会将错误信息报告给TestResult。这些宏定义的说明如下：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; "><p>CPPUNIT_ASSERT(condition)：判断condition的值是否为真，如果为假则生成错误信息。</p><p>CPPUNIT_ASSERT_MESSAGE(message, condition)：与CPPUNIT_ASSERT类似，但结果为假时报告messsage信息。</p><p>CPPUNIT_FAIL(message)：直接报告messsage错误信息。</p><p>CPPUNIT_ASSERT_EQUAL(expected, actual)：判断expected和actual的值是否相等，如果不等输出错误信息。</p><p>CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual)：与CPPUNIT_ASSERT_EQUAL类似，但断言失败时输出message信息。</p><p>CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)：判断expected与actual的偏差是否小于delta，用于浮点数比较。</p><p>CPPUNIT_ASSERT_THROW(expression, ExceptionType)：判断执行表达式expression后是否抛出ExceptionType异常。</p><p>CPPUNIT_ASSERT_NO_THROW(expression)：断言执行表达式expression后无异常抛出。</p></div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">接下来再看看TestFixture和TestCaller的组合使用：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">#include&nbsp;&lt;cppunit/TestCase.h&gt;<br />#include&nbsp;&lt;cppunit/TestResult.h&gt;<br />#include&nbsp;&lt;cppunit/TestResultCollector.h&gt;<br />#include&nbsp;&lt;cppunit/TextOutputter.h&gt;<br />#include&nbsp;&lt;cppunit/TestCaller.h&gt;<br />#include&nbsp;&lt;cppunit/TestRunner.h&gt;<br /><br />//&nbsp;定义测试类<br />class&nbsp;StringTest&nbsp;:&nbsp;public&nbsp;CppUnit::TestFixture<br />{<br />public:<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;setUp()&nbsp;//&nbsp;初始化<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1&nbsp;=&nbsp;"Hello,&nbsp;world";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str2&nbsp;=&nbsp;"Hi,&nbsp;cppunit";<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;tearDown()&nbsp;//&nbsp;清理<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;testSwap()&nbsp;//&nbsp;测试方法1<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;str1&nbsp;=&nbsp;m_str1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;str2&nbsp;=&nbsp;m_str2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1.swap(m_str2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT(m_str1&nbsp;==&nbsp;str2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT(m_str2&nbsp;==&nbsp;str1);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;testFind()&nbsp;//&nbsp;测试方法2<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;pos1&nbsp;=&nbsp;m_str1.find(',');<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;pos2&nbsp;=&nbsp;m_str2.rfind(',');<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT_EQUAL(5, pos1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT_EQUAL(2, pos2);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />protected:<br />&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1;<br />&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str2;<br />};<br /><br />int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResult&nbsp;r;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResultCollector&nbsp;rc;<br />&nbsp;&nbsp;&nbsp;&nbsp;r.addListener(&amp;rc);&nbsp;//&nbsp;准备好结果收集器&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestRunner&nbsp;runner;&nbsp;//&nbsp;定义执行实体<br />&nbsp;&nbsp;&nbsp;&nbsp;runner.addTest(new&nbsp;CppUnit::TestCaller&lt;StringTest&gt;("testSwap",&nbsp;&amp;StringTest::testSwap));&nbsp;//&nbsp;构建测试用例1<br />&nbsp;&nbsp;&nbsp;&nbsp;runner.addTest(new&nbsp;CppUnit::TestCaller&lt;StringTest&gt;("testFind",&nbsp;&amp;StringTest::testFind));&nbsp;//&nbsp;构建测试用例2<br />&nbsp;&nbsp;&nbsp;&nbsp;runner.run(r);&nbsp;//&nbsp;运行测试<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TextOutputter&nbsp;o(&amp;rc,&nbsp;std::cout);<br />&nbsp;&nbsp;&nbsp;&nbsp;o.write();&nbsp;//&nbsp;将结果输出<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;rc.wasSuccessful()&nbsp;?&nbsp;0&nbsp;:&nbsp;-1;<br />}</div><span style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">编译后运行结果为：</span><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">OK (2 tests)</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">上面的代码从功能上讲没有什么问题，但编写起来太繁琐了，为此，我们可以借助CppUnit定义的一套辅助宏，将测试用例的定义和注册变得自动化。上面的代码改造后如下：</p><div style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">#include&nbsp;&lt;cppunit/TestResult.h&gt;<br />#include&nbsp;&lt;cppunit/TestResultCollector.h&gt;<br />#include&nbsp;&lt;cppunit/TextOutputter.h&gt;<br />#include&nbsp;&lt;cppunit/TestRunner.h&gt;<br />#include&nbsp;&lt;cppunit/extensions/HelperMacros.h&gt;<br /><br /><br />//&nbsp;定义测试类<br />class&nbsp;StringTest&nbsp;:&nbsp;public&nbsp;CppUnit::TestFixture<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_TEST_SUITE(StringTest);&nbsp;&nbsp;//&nbsp;定义测试包<br />&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_TEST(testSwap);&nbsp;&nbsp;//&nbsp;添加测试用例1<br />&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_TEST(testFind);&nbsp;&nbsp;//&nbsp;添加测试用例2<br />&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_TEST_SUITE_END();&nbsp;&nbsp;//&nbsp;结束测试包定义<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />public:<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;setUp()&nbsp;//&nbsp;初始化<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1&nbsp;=&nbsp;"Hello,&nbsp;world";<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str2&nbsp;=&nbsp;"Hi,&nbsp;cppunit";<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;tearDown()&nbsp;//&nbsp;清理<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;testSwap()&nbsp;//&nbsp;测试方法1<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;str1&nbsp;=&nbsp;m_str1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;str2&nbsp;=&nbsp;m_str2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1.swap(m_str2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT(m_str1&nbsp;==&nbsp;str2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT(m_str2&nbsp;==&nbsp;str1);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;testFind()&nbsp;//&nbsp;测试方法2<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;pos1&nbsp;=&nbsp;m_str1.find(',');<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;pos2&nbsp;=&nbsp;m_str2.rfind(',');<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT_EQUAL(5, pos1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPPUNIT_ASSERT_EQUAL(2, pos2);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />protected:<br />&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str1;<br />&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_str2;<br />};<br /><br />CPPUNIT_TEST_SUITE_REGISTRATION(StringTest);&nbsp;//&nbsp;自动注册测试包<br /><br />int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResult&nbsp;r;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestResultCollector&nbsp;rc;<br />&nbsp;&nbsp;&nbsp;&nbsp;r.addListener(&amp;rc);&nbsp;//&nbsp;准备好结果收集器&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TestRunner&nbsp;runner;&nbsp;//&nbsp;定义执行实体<br />&nbsp;&nbsp;&nbsp;&nbsp;runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());<br />&nbsp;&nbsp;&nbsp;&nbsp;runner.run(r);&nbsp;//&nbsp;运行测试<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CppUnit::TextOutputter&nbsp;o(&amp;rc,&nbsp;std::cout);<br />&nbsp;&nbsp;&nbsp;&nbsp;o.write();&nbsp;//&nbsp;将结果输出<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;rc.wasSuccessful()&nbsp;?&nbsp;0&nbsp;:&nbsp;-1;<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; text-align: left; background-color: #ffffff; ">CppUnit的简单介绍就到此，相信你已经了解了其中的基本概念，也能够开发单元测试代码了。<br /><br />转自：<a href="http://blog.csdn.net/freefalcon/article/details/753819">http://blog.csdn.net/freefalcon/article/details/753819</a></p><img src ="http://www.cppblog.com/tankzhouqiang/aggbug/166911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tankzhouqiang/" target="_blank">周强</a> 2012-03-01 20:25 <a href="http://www.cppblog.com/tankzhouqiang/archive/2012/03/01/166911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>