首先还是从如何测试开始剖析代码把,以下就是ExampleTestCase.h的代码
画面第一行:ExampleTestCase就是我们为一个类生成的测试类,他必须要继承自测试框架类CPPUNIT_NS::TestFixture这样才可以正常测试。
画面第三~八行:其中,宏CPPUNIT_TEST_SUITE(), 宏CPPUNIT_TEST()和宏CPPUNIT_TEST_SUITE_END()被设计用来简化创建测试包的过程。当然要构造一个正常的测试还有一个前提,就是在ExampleTestCase.h这个文件中加入#include <cppunit/extensions/HelperMacros.h>,因为这几个简化映射用的宏都是存在于HelperMacros.h中
先介绍第一个宏CPPUNIT_TEST_SUITE( ExampleTestCase );
画面第七行:测试构造类被重新定义为TestFixtureType名字方便下面使用。
画面第十行:getTestNamer__是类的静态方法,主要是利用C++的RTTI信息取得用户写的TestFixture类的类名字,getTestNamer__的返回值是一个测试类的对象TestNamer。TestNamer这个类定义如下,比较的简单,这里就不作说明了
请大家注意宏:CPPUNIT_TESTNAMER_DECL,所以说这个测试类的名字就和这两个参数当字符串相连接,以下是CPPUNIT_TESTNAMER_DECL
让我们再次把目光回到CPPUNIT_TEST_SUITE的代码上。
代码第17-18行:把TestSuiteBuilderContext类型重新声明为TestSuiteBuilderContextType,又是变个名称而已,但是TestSuiteBuilderContext又是什么东西呢?在这里用到了一个设计模式Builder,稍后我们再来看它的代码。
代码第21行:声明了一个静态的公有函数addTestsToSuite,加入测试用例到测试组,参数是一个TestSuiteBuilderContextBase,这个就是Builder设计模式中所有ConcreteBuilder的基类了。接下来我们看看如何添加测试用例进去。看CPPUNIT_TEST和CPPUNIT_TEST_SUITE_ADD_TEST宏的定义:
这里new了一个TestCaller,TestCaller继承自testcase类,具体的我们先放放。"#testMethod"就很明显了,传入了测试参数的名称字符串。&TestFixtureType::testMethod是一个指向成员函数的指针。context.makeFixture() 是用来创建测试装置的。
接下来让我们看看这组宏的结束CPPUNIT_TEST_SUITE_END:
代码第2行:addTestsToSuite函数结束的标志。
代码第4行:静态的suite函数,返回测试包对象的指针。
代码第6行:getTestNamer__方法是在同名的那个START宏里面定义的。
代码第9行:一个装置器的工厂。
代码第10-12行:Builder基类的初始化。
代码第13行:addTestsToSuite调用的地方,调用后就把测试用例加入到了TestSuiteBuilderContextBase::m_tests中。
代码第14行:suite.release放弃包装在智能指针里面的内容,把它释放出来给外面。如果不执行它,智能指针会自动对资源进行回收。
代码第17行:就是一定要让这个宏的后面加上分号才可以正常编译通过的一个方法。
看了上面的分析,知道了addTestsToSuite方法是注册测试用例到TestSuiteBuilderContextBase中的方法,那么测试用例不是用工厂来创建的阿,那么这些测试用例的工厂注册又在哪里呢?在CPPUNIT_TEST_SUITE_REGISTRATION和CPPUNIT_TEST_SUITE_NAMED_REGISTRATION2个宏里,细心的人一定看到了,在ExampleTestCase.cpp的最上面,使用了CPPUNIT_TEST_SUITE_REGISTRATION宏。
到这里几个最主要的宏的介绍都全了。一行短短的宏,把这么多信息包含进了里面去。让我想到了mfc中宏的应用。最后是TestSuiteBuilderContextBase.h
现在看来,这个类的功能就一目了然了把,TestSuiteBuilderContextBase聚集了装置器工厂和一组测试用例。一组测试用例(一组用例的名字是主测类名)在CPPUNIT_TEST_SUITE_REGISTRATION中都进行了注册。在添加测试用例TestCaller的时候,需要用到装置器工厂。
TestCaller.h
这个类的模板参数Fixture就是装置器,为了更方便宏的使用才用了模板参数。看代码可以知道,这里用了策略模式。一个类的所有测试用例都用了同一个装置器。而具体的运行哪个策略,可以根据成员函数的指针指向的函数来确定。概括的说,TestCaller其实是一个辅助类,负责把ExampleTestCase和TestCase关联起来。