[Orthodox]
相关文件:Orthodox.h
该类实现了正规测试的功能。它派生自TestCase,是一个模板类,有一个类型参数ClassUnderTest,代表将要运行的测试。所谓正规测试,就是对待测类(即ClassUnderTest)执行一组简单的测试,确保其至少具有如下基本操作:
- default ctor
- operator==和operator!=
- assignment(即operator=)
- operator!
- safe passage(即copy ctor)
若其中任何一项没有通过测试,则模板类就不会实例化。否则,实例化后将检查这些操作的语义是否正确。当你需要确认一组待测类具有相同表现时,采用被模板化的测试用例非常有用,Orthodox就是一个很好的例子。可以想见,在实际工作中,我们也可以效仿Orthodox的做法,从而“扩展”CppUnit以适应自己的特定环境。
以下代码演示了如何将一个复数类的正规测试添加到测试包中:
TestSuite *suiteOfTests = new TestSuite;
suiteOfTests->addTest (new ComplexNumberTest ("testAdd");
suiteOfTests->addTest (new TestCaller<Orthodox<Complex> > ()); // 非常简单
来看一下Orthodox的定义:
template <typename ClassUnderTest> class Orthodox : public TestCase
{
public:
Orthodox () : TestCase ("Orthodox") {}
protected:
ClassUnderTest call (ClassUnderTest object);
void runTest ();
};
唯一需要解释的就是runTest方法,Orthodox是如何检查ClassUnderTest是否符合要求的呢:
template <typename ClassUnderTest>
void Orthodox<ClassUnderTest>::runTest ()
{
// 确保default ctor被定义,否则无法通过编译
ClassUnderTest a, b, c;
// 确保operator==被定义,否则无法通过编译
// 同时检查operator==的语义
CPPUNIT_ASSERT (a == b);
// 确保operator!、operator=和operator!=被定义
// 否则无法通过编译
// 同时检查operator!=的语义
b.operator= (a.operator! ());
CPPUNIT_ASSERT (a != b);
// 检查operator!和operator==的语义
b = !!a;
CPPUNIT_ASSERT (a == b);
b = !a;
// 以下检查copy ctor是否被定义及其语义正确与否
c = a;
CPPUNIT_ASSERT (c == call (a));
c = b;
CPPUNIT_ASSERT (c == call (b));
}
这里的call是辅助函数,“迫使”编译器调用copy ctor,以检查safe passage:
template <typename ClassUnderTest>
ClassUnderTest Orthodox<ClassUnderTest>::call (ClassUnderTest object)
{
return object;
}
所有的奥妙就在上面这几行代码中。
[TestSetUp]
相关文件:TestSetUp.h,TestSetUp.cpp
同样派生自TestDecorator,它使测试类具有了SetUp和TearDown的特性。关于这两个特性请见core部分的TestFixture。
该类定义了两个protected属性的虚函数,以供派生类覆盖:
protected:
virtual void setUp();
virtual void tearDown();
此外,就是子类化了run方法:
void TestSetUp::run( TestResult *result )
{
setUp();
TestDecorator::run(result);
tearDown();
}
[后记]
正如我在“CppUnit源码解读(1)”一文中所说,这一系列的文章是从《CppUnit源码解读》中摘选出来的,并且我认为是主要部分的章节。 我打算将本文做为这一系列文章的结尾,不过,对此仍感兴趣的朋友将可以在我的主页上找到这一系列文章的完整版本:http://morningspace.51.net/resource/cppunit/cppunit_anno.html。
当然,所谓主要也只是个人的主观划分。比如CppUnit中另一个重要环节——结果输出,这里就没有提到,那是Observer Pattern的用武之地。另外,CppUnit的类厂实现机制也是很有特色的。就这些议题,你将可以在完整版中找到。
这么做,是出于如下的考虑:文章的内容毕竟出于源码的个人阅读笔记(最初是写给自己看的:),并且由于时间关系,我也无法将其做得十分精致(比如就像有人抱怨的没有画上图示,类图等等:)。看久了难免让人觉得有点像记流水帐,让人觉得乏味。与其如此,到不如让那些不介意流水账的朋友来网站看后续内容,而介意者也就无需再继续看下去了:)
再次重申,本文系源码笔记,如果你想了解有关CppUnit的使用,请参考其他文献,据我所知CSDN的文档中心里就有一篇入门性的文章:)
—— Morning
