在测试工作中,需要接触到各种类型的测试工具。一般来说,有以下一些类型的工具:
测试管理工具:可以帮助完成测试计划、跟踪测试运行结果等的工具。这类工具还包括有助于需求、设计、编码测试及缺陷跟踪的工具;
静态分析工具:分析代码而不执行代码。这种工具检测某些缺陷比用其它方法更有效,开销也更小。这种工具一般可以度量代码的各种指标,如McCabe测定复杂度,Logiscope度量代码和规范的复合度等等;
覆盖率工具:这种工具评估通过一系列测试后,软件被执行的程度。这种工具大量的被应用于单元测试中,如PureCoverage、TrueCoverage、Logiscope等;
动态分析工具:这种工具评估正在运行的系统。例如,检查系统运行过程中的内存使用情况,是否有内存越界、内存泄露等等,这类工具有Purify、BoundChecker等;
测试执行工具:这类工具可使测试能够自动化进行,并且各个层次(单元测试、集成测试、系统测试)的执行工具都有。例如系统测试阶段有功能测试自动化工具,如Robot、Winrunner、SilkTest等;还有性能测试工具,如Loadrunner、SilKPerformer等。
白盒测试工具主要有:
内存资源泄漏检查:Numega中的bouncechecker,Rational的Purify
代码覆盖率检查:Numega中的truecoverage,Rational的Purecoverage,Telelogic公司的logiscope, Macabe公司的Macabe
代码性能检查:Numega中的truetime,Rational的Quantify
代码静态度量分析质量检查工具:logiscope和Macabe
黑盒测试工具主要有:
客户端功能测试:MI公司的winrunner,compuware的qarun,Rational的robot
服务器端压力性能测试: MI公司的winload,compuware的qaload,Rational的SQA load等等
Web测试工具:MI公司的Astra系列,rsw公司的e-test suite
测试管理工具:rational的test manager,compuware的qadirector等
缺陷跟踪工具:trackrecord,Testtrack
单元测试工具:
测试框架: delphi dunit
java junit
c++ cppunit
Visual Basic VBUnit
(.NET platform) NUnit
二、
使用引用计数的方法实现的内存垃圾回收不能自动回收循环引用的内存,循环引用的内存需要使用手工进行释放,但手工释放很可能由于编程人员的失误导致内存泄漏,所以必须检查是否存在内存泄漏。要完成这项任务,只要在程序退出时检查一下哈希表中还有哪些内存的引用计数不为0,就可以知道有哪些内存还没有被释放,内存没有被释放的原因有以下两种。
① 内存是供全局使用的,必须等到要退出时才能释放;
② 内存中有循环引用,导致不能释放。
还需要知道哈希表中保存的内存地址指向的内存是在程序的哪一行分配的,才能定位到具体发生泄漏的位置。C语言中有一个宏可以获取源程序中的行号,下面就用这个宏来实现内存泄漏检查。
内存泄漏只是在软件的DEBUG版本才需要用到,因此下面就来设计一个DEBUG版本的内存垃圾回收。
首先要修改内存中需要保存的数据,除了保存引用计数外,还需要保存分配这块内存的源程序文件名和行号,还要保存分配内存的大小信息。为方便起见,可以将引用计数和内存大小保存在分配内存的头部,行号和文件名保存在分配内存的尾部。
关于获取源程序文件名和行号,可以使用宏_FILE_和_LINE_来获取,要注意的是,_LINE_和_FILE_是调用它们的地方的源文件名和行号,如果简单地在GC_Malloc()函数中使用这两个宏,那么所有调用GC_Malloc()函数的地方获得的源文件名和行号都是 GC_Malloc()函数的源文件名和行号,所有获取的源文件名和行号均相同,显然达不到预想的目的。
预想的目的是为了获取调用GC_Malloc()处的源文件名和行号,因此需要将GC_Malloc()函数定义成宏,这样在调用它的地方就会将编码展开,便能得到正确的调用GC_Malloc()处的源文件名和行号,有助于确认发生内存泄漏的位置及原因。
通常只要在程序的调试版本中检查内存泄漏就可以了,修改后对应的GC_Malloc()和GC_Free()函数如下。
#ifdef_DEBUG
#defineGC_Malloc(size)
{
void*p;
INT*q;
char*psz;
p=malloc(size+DOUBLE_INT_LEN+INT_LEN+strlen(__FILE__)+1);
if(p==NULL)
{
GC_Collect();
p=malloc(size+DOUBLE_INT_LEN+INT_LEN+strlen(__FILE__)+1);
if(p==NULL)
{
returnNULL;
}
}
HashTable_Insert(g_pTable,p,HashInt);
*((INT*)p)=0;
*((INT*)p+1)=size;
q=(INT*)((char*p)+size+DOUBLE_INT_LEN);
*q=__LINE__;
psz=(char*)p+size+DOUBLE_INT_LEN+INT_LEN;
strcpy(psz,__FILE__);
return(void*)((char*)p+DOUBLE_INT_LEN);
}
/** 垃圾内存收集算法的内存释放函数
@param void*p——要释放的内存地址
@return void——无
*/
voidGC_Free(void*p)
{
void*pFree=(void*)((char*)p-DOUBLE_INT_LEN);
free(pFree);
}
#endif
内容导航
下面就来实现内存泄漏的检查。内存泄漏检查只需要在程序退出时检查哪些内存的引用计数不为0,只要对哈希表做一个遍历操作就可以获取哪些内存的引用计数不为0,编码如下。
/** 垃圾内存收集算法的内存泄漏检查函数
@return void——无
*/
voidGC_CheckMemoryLeak()
{
void*p;
HashTable_EnumBegin(g_pTable);
while((p=HashTable_EnumNext(g_pTable))!=NULL)
{
INT*pRef;
INT*pSize;
INT*pLine;
char*pszFile;
pRef=(INT*)p;
pSize=pRef+1;
if(*pRef !=0) /*判断引用计数是否为0*/
{
pLine=(INT*)((char*)p+*pSize+DOUBLE_INT_LEN);
pszFile=(char*)pLine+INT_LEN;
printf("File:%s,Line:%dhavememoryleak.\n",pszFile,*pLine);
}
}
}
注意:程序中使用了printf()函数将文件名和行号打印出来,这里使用printf()函数只是做一个示意,实际应用中可能需要改成其他类型的信息输出函数。
可以使用函数调用来实现在程序退出时自动调用GC_CheckMemory()函数。
atexit(GC_CheckMemoryLeak);
这里使用了C标准库的atexit()函数,这个函数是在整个程序退出时调用它的参数指向的函数来执行,但是调用的时间比全局变量的释放要早,所以如果使用了全局变量,全局变量也被当作泄漏报告出来。