|
驱动无非就是使被测试函数得以执行的代码,通常是很简单的。例如:
int main()
{
//初始化
int ret = Max();
//判断结果是否符合预期
}
当然,实际应用中,不可能每个测试都使用一个main函数,因此需要对驱动进行组织和管理。cppunit的主要功能就对测试的组织,以及显示测试结果。
对于大规模的项目,可测性是可想而知的,不见得是设计的问题,因为事物本身是互相纠缠的,代码间的大量耦合无法避免,打桩是解耦合的常用手段。 另外,并行开发也通常因相关代码未实现而需打桩。
桩代码大概是这样子的:
int fun1(){return 0;};
int fun2(){return 0;};
主要功能是让链接能够通过。
打桩是很简单的技术,如果用手工方法的话,大致过程是这样的:
1)编译链接源文件,编译错误通常跟打桩无关的,要先解决.
2)编译过了后,如果产生"未定义的外部符号"之类的链接错误,如VC6的L2001错误,就是缺少符号定义,可能是函数,也可能是非局部全量.
3)根据缺少的函数或变量的声明,编写函数实现或变量定义.
如果使用工具,工作原理也很简单,自己写一个工具也不需要多高的技术:
1)对源代码进行解析,找出缺少的定义
2)根据声明生成定义.
但打桩导致一个大问题,导致测试可能无法进行,例如:
int a,b;
a = subfunc(&b, arg); //arg是函数的一个参数
if(b > 0) {...}
else if(a > 0){...}
...
如果subfunc是用桩来代替的,桩通常会是这个样子:int subfunc(int* b, DATA* arg){return 0;},即什么也不做,直接返回0,这样,a永远是0,b永远未初始化,根本就测试不下去,称为失真。修改桩代码一般也不行,因为每个用例,a和b的值应该是不同的,不可能执行一个用例又去改一下。为了解决失真,需要使用仿真技术,在用例中直接设置subfunc的行为,例如:
用例一,subfunc返回1, 并把b的值设为2
用例二,subfunc返回10, 并把b的值设为20
....
有了隔离和仿真,就可以对大项目的现有代码进行随意的分割和测试了。
Visual Unit 2.2可以自动完成上述工作,包括驱动/桩/仿真。目前,我所知道的最大的成功案例,是测试某电信企业的约有一千万行代码的项目。楼主不妨一试。 |
|