首先看一下类的继承结构吧(斜体代表抽象类):
最后存在于内存中的TestSuite和TestCaller对象都是从Test派生而来,TestSuite有这样一个属性:
private:
CppUnitVector<Test *> m_tests;
作为component,它可以有很多leaf节点,但是由于它也是从Test派生而来,所以它又可以成为别的component的页节点。
cppunit运行时,会将一个TestSuite的所有子节点都运行完,不管其是component还是leaf。它能这样做关键在于它的run函数,TestSuite并没有实现自己的run函数,它从TestComponent继承run函数,TestComponent的run函数实现如下:
void
TestComposite::run( TestResult *result )
{
doStartSuite( result );
doRunChildTests( result );
doEndSuite( result );
}
关键在于第二句,doRunChildTests函数实现如下:
void
TestComposite::doRunChildTests( TestResult *controller )
{
int childCount = getChildTestCount();
for ( int index =0; index < childCount; ++index )
{
if ( controller->shouldStop() )
break;
getChildTestAt( index )->run( controller );
}
}
注意最后一句,如果getChildTestAt( index )得到的是一个TestSuite对象,那么它又会调用上面的TestComponent::run,这样迭代下去;如果是一个TestCaller对象,那么就会调用TestCaller::run函数,其实现代码如下:
/// Run the test and catch any exceptions that are triggered by it
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 );
}
由此可以看出TestSuite和TestCaller的run函数的各自实现是很关键的,这样可以保证整棵树完整被运行。顺便提一下,TestComposite这个类只有一个“std::string m_name”属性,但是它却能实现run函数,如果让我自己来设计的话,我可能会将这个run函数的详细实现放到TestSuite对象中,因为TestSuite才有保存Test的容器。但是TestComposite实现这个函数有其合理性。
另外还有一处用到了工厂模式。TestFactoryRegistry从TestFactory派生,同时其有一个属性:
typedef CppUnitSet<TestFactory *, std::less<TestFactory*> > Factories;
Factories m_factories;
所以工厂也可以组成一棵树,大工厂包含小工厂,小工厂再包含小工厂。工厂的makeTest方法返回的是TestSuite对象,所有一个树形的工厂生产出来的TestSuite对象也会维持其相应的树状。cppunit也提供了这样一个宏来简化我们的操作,该宏定义如下:
#define CPPUNIT_REGISTRY_ADD( which, to ) \
static CPPUNIT_NS::AutoRegisterRegistry \
CPPUNIT_MAKE_UNIQUE_NAME( autoRegisterRegistry__ )( which, to )
当然我们也可以自己手工来操作。比如这样:
CPPUNIT_NS::TestFactoryRegistry::getRegistry("My Test").addRegistry("All Tests");
这样就有意思地将"All Tests"变成了"My Test"工厂的子工厂。
最后用到组合的模式的地方是protectchain,这个类从protector派生,其内部又有一个deque容器保存protector指针,这样就可以极大地扩展protectchain。不过cppunit中起作用也就是一个default protector,并没有复杂的应用。
![cppunit与组合模式 - 绚丽也尘埃 - 处女地](http://img.bimg.126.net/photo/YJ2_OzwsyhNcGcJQJq67OQ==/2850778564126035060.jpg)
最后存在于内存中的TestSuite和TestCaller对象都是从Test派生而来,TestSuite有这样一个属性:
private:
CppUnitVector<Test *> m_tests;
作为component,它可以有很多leaf节点,但是由于它也是从Test派生而来,所以它又可以成为别的component的页节点。
cppunit运行时,会将一个TestSuite的所有子节点都运行完,不管其是component还是leaf。它能这样做关键在于它的run函数,TestSuite并没有实现自己的run函数,它从TestComponent继承run函数,TestComponent的run函数实现如下:
void
TestComposite::run( TestResult *result )
{
doStartSuite( result );
doRunChildTests( result );
doEndSuite( result );
}
关键在于第二句,doRunChildTests函数实现如下:
void
TestComposite::doRunChildTests( TestResult *controller )
{
int childCount = getChildTestCount();
for ( int index =0; index < childCount; ++index )
{
if ( controller->shouldStop() )
break;
getChildTestAt( index )->run( controller );
}
}
注意最后一句,如果getChildTestAt( index )得到的是一个TestSuite对象,那么它又会调用上面的TestComponent::run,这样迭代下去;如果是一个TestCaller对象,那么就会调用TestCaller::run函数,其实现代码如下:
/// Run the test and catch any exceptions that are triggered by it
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 );
}
由此可以看出TestSuite和TestCaller的run函数的各自实现是很关键的,这样可以保证整棵树完整被运行。顺便提一下,TestComposite这个类只有一个“std::string m_name”属性,但是它却能实现run函数,如果让我自己来设计的话,我可能会将这个run函数的详细实现放到TestSuite对象中,因为TestSuite才有保存Test的容器。但是TestComposite实现这个函数有其合理性。
另外还有一处用到了工厂模式。TestFactoryRegistry从TestFactory派生,同时其有一个属性:
typedef CppUnitSet<TestFactory *, std::less<TestFactory*> > Factories;
Factories m_factories;
所以工厂也可以组成一棵树,大工厂包含小工厂,小工厂再包含小工厂。工厂的makeTest方法返回的是TestSuite对象,所有一个树形的工厂生产出来的TestSuite对象也会维持其相应的树状。cppunit也提供了这样一个宏来简化我们的操作,该宏定义如下:
#define CPPUNIT_REGISTRY_ADD( which, to ) \
static CPPUNIT_NS::AutoRegisterRegistry \
CPPUNIT_MAKE_UNIQUE_NAME( autoRegisterRegistry__ )( which, to )
当然我们也可以自己手工来操作。比如这样:
CPPUNIT_NS::TestFactoryRegistry::getRegistry("My Test").addRegistry("All Tests");
这样就有意思地将"All Tests"变成了"My Test"工厂的子工厂。
最后用到组合的模式的地方是protectchain,这个类从protector派生,其内部又有一个deque容器保存protector指针,这样就可以极大地扩展protectchain。不过cppunit中起作用也就是一个default protector,并没有复杂的应用。