CppUnit-code

2026/1/17 4:36:08

result->addError( this, new Exception( e.what() ) ); }

catch (...) {

// 截获其余未知异常,一网打尽

Exception *e = new Exception( \ result->addError( this, e ); }

// 资源回收 try {

tearDown(); }

catch (...) {

result->addError( this, new Exception( \ } }

catch (...) {

result->addError( this, new Exception( \ }

result->endTest( this ); }

可以看到,run方法定义了一个测试类运行的基本行为及其顺序:

? ? ?

setUp:准备 runTest:开始 tearDown:结束

而TestCase作为抽象类无法确定测试的具体行为,因此需要留待派生类解决,这就是Template Method Pattern。事实上,该pattern在framework中是很常见的。因此一个完整测试的简单执行方法是,从TestCase派生一个类,重载相关方法,并直接调用run方法(正如TestFixture中所提到的)。

有意思的是,TestCase中还有run的另一个版本,它没有形参,而是创建一个缺省的TestResult,然后调用前述run方法。不过好像没怎么用到,大概是先前调试时未及清理的垃圾代码,也难怪会有“FIXME: what is this for?”这样的注释了。 TestCase有两个ctor:

TestCase( std::string Name ); // 测试类的名称 TestCase();

后者主要用于TestCaller,因为在使用TestCaller时,需要一个default ctor

此外,TestCase将copy ctor和operator=声明为private属性,以防止误用。

[TestSuite]

相关文件:TestSuite.h,TestSuite.cpp

一组相互关联的测试用例,构成了一个测试包,这就是TestSuite,也就是Composite Pattern中的Composite。和TestCase一样,也派生自Test,只是没有fixture特性。除了测试类的名称外,在TestSuite中还维护了一个测试对象数组,它被声明为private属性:

std::vector m_tests; const std::string m_name;

来看一下TestSuite的run方法是如何实现的,并请留意morning的注释:

void TestSuite::run( TestResult *result ) {

// 遍历vector

for ( std::vector::iterator it = m_tests.begin(); it != m_tests.end(); ++it ) {

// 可能中途终止

if ( result->shouldStop() ) break;

Test *test = *it; // 调用每个test自己的run

// 可能是TestCase实例,也可能是TestSuite实例, // 后者形成递归,但此处却全然不知 test->run( result ); } }

关于TestResult及其shouldStop方法,稍后会讲到。不过此处的break,到也算是活用Composite Pattern的一个简单范例。从效率的角度考虑,当确信不必再执行后续的test时,即可直接返回,而不是照葫芦画瓢,简单的调用一下test的run方法。

既然TestResult派生自Test,那么countTestCases又是如何实现的呢:

int TestSuite::countTestCases() const {

int count = 0;

// 遍历vector

for ( std::vector::const_iterator it = m_tests.begin(); it != m_tests.end(); ++it )

count += (*it)->countTestCases(); // 递归调用每个test的countTestCases,并累加

return count; }

至于addTest,自然是不能少的,它对应于Composite的Add方法:

void TestSuite::addTest( Test *test ) {

m_tests.push_back( test ); // 将test添加到测试对象数组的尾端 }

不过请注意,addTest方法并未出现于抽象类Test中,关于这类设计上的权衡在GoF中,Composite Pattern一节有专门的论述。

TestSuite管理着其下所属诸测试对象的生命周期,在dtor中,它会调用deleteContents方法:

void TestSuite::deleteContents() {

for ( std::vector::iterator it = m_tests.begin(); it != m_tests.end(); ++it) delete *it; m_tests.clear(); }

此外,TestSuite还为外部访问其所属测试对象提供了接口,因为返回值是const &类型的,所以是read-only的:

const std::vector &getTests() const;

测试结果记录

从这里开始,将要讲述core中,测试结果记录的相关部分。

CppUnit是支持多线程的,你可以在一个线程中执行测试,在另一个线程中收集测试结果;或者在不同线程中并行执行多个测试,而用一个线程收集测试结果。framework中为此提供了简单而必要的支持。

[SynchronizedObject]

相关文件:SynchronizedObject.h,SynchronizedObject.cpp

SynchronizedObject用来管理一个被同步对象,前面提到的TestResult就是从该类派生的。所谓被同步对象,是指其成员会被多个线程并发使用。

SynchronizedObject定义了一个public属性的abstract inner class——SynchronizationObject,代表具备同步属性的对象:

class SynchronizationObject {

public:

SynchronizationObject() {}

virtual ~SynchronizationObject() {} virtual void lock() {} virtual void unlock() {} };

此类定义了互斥锁功能,但具体行为需在其派生类中实现。不同环境下的实现方式想必也不尽相同。随CppUnit源码所附的范例中有个MfcSynchronizationObject就是SynchronizationObject的子类,它使用了MFC的CCriticalSection:

class MfcSynchronizationObject

: public CppUnit::SynchronizedObject::SynchronizationObject {

CCriticalSection m_syncObject; public: void lock() {

m_syncObject.Lock(); }

void unlock() {

m_syncObject.Unlock(); } };

SynchronizedObject还定义了一个protected属性的inner class——ExclusiveZone,作为内部使用的辅助类。它用于在当前作用域内锁定一个SynchronizationObject的实例。其实现类似于std::auto_ptr,它持有一个指向SynchronizationObject对象的指针,ctor中调用lock,dtor中调用unlock:

class ExclusiveZone {

SynchronizationObject *m_syncObject;


CppUnit-code.doc 将本文的Word文档下载到电脑
搜索更多关于: CppUnit-code 的文档
相关推荐
相关阅读
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 10

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219