可能大家都有这样的疑问:测试用例运行过程中,要是出现错误,异常甚至崩溃的情况下是在哪里捕捉到的呢?那么我们就从这里入手慢慢的来了解TestResult的各个机能。
请大家先回忆一下TestCase::Run方法。
在这个方法里面,其实调用的是TestResult的protect()方法,看到这里也不难推测TestResult::protect()里面是真正执行并捕捉错误的地方。
TestResult是一个记录所有测试结果的类。而程序运行的防错机制:try-catch放在了Protector类的子类中。先看看Protector类的源码。
Protector.h
这里的reportError(),reportFailure()等方法,是在子类的错误捕捉到以后为了输出而准备的。具体输出什么如何输出大家看代码就可以了。而protect()方法是纯虚函数,真正需要保护的东西是在它的子类实现。这样做的目的很明确,错误的输出是固定的,所以放在父类,而如何保护测试用例的执行(也就是try-catch)放在子类也是方便修改和便于扩展。
DefaultProtector.h
以上是DefaultProtector的代码,它就是继承了Protector类,并实现了Protector类的纯虚函数protect()。这个类才是真正执行测试用例保护测试用例的地方。
接下去的话题将围绕protect()而展开。知道protect()的作用后,那么它如何调用,什么时候调用呢?还有两个参数分别代表什么意思。
ProtectorContext.h
这个类将Test,TestResult这些对象聚集在了一起,看过DefaultProtector代码就知道,聚集在一起是因为当发生异常的时候需要这些信息来输出。
Protector::protect()的另外一个参数是Functor,也就是函数对象。在介绍TestCase的时候,就已经提到过Functor了,而这里将在一次说明它
定义函数对象最主要是为了实现命令模式,初始化函数对象的时候把必要的东西通过构造函数预先传入,用重载操作符实现回调。
在ProtectorChain类里面,定义了一个inner class叫做ProtectFunctor,ProtectFunctor就是继承自Functor。
ProtectFunctor继承自Functor,而继承自ProtectFunctor里面又有一个成员是Functor,哈哈。一看就知道这个是装饰者模式对这个函数对象内容的扩展。
上面代码第15行:m_protector->protect( m_functor, m_context );
m_protector对象的类有个体子类和组合子类之分,所以有了多态的灵活特性。具体参见下面的ProtectorChain。
m_functor函数对象就是实现装饰者模式的根本。
最后也是这个设计中最美妙的地方:ProtectorChain.h
上面代码第三行:ProtectorChain是Protector的子类,再看第39行:ProtectorChain里面存放着Protector的一个双端链表。如果DefaultProtector子类是叶子节点的话,ProtectorChain应该就是组合。这些应该也是组合模式的一种不完全应用把。
代码第35行:这个inner class的类(函数对象)代码已经在先前给出了。
最后的最后也就是ProtectorChain.cpp也是最核心的代码块
关于错误异常这方面的类结构就如上所示,同时将好几个设计模式应用在了里面,至于具体如何输出错误异常等信息,将在后面继续分析之。
总结上面这些代码:protect是最最核心的部分 其作用是对执行函数(实际上是函数对象)的错误信息(包括断言和异常等)进行捕获,从而实现对测试结果的统计。