在软件开发中,程序自测是一个永远绕不开的话题。很多开发人员以写出难的代码为荣,却不注意对自己编写的代码进行测试,导致最终到达客户手中的产品质量低下,bug频出,损害公司形象。对于一个开发者来说,应该把开发和自测放在同等重要的位置,我们花在自测上的时间不亚于开发。能否对自己编写的代码进行全面的自我测试,也是检验开发人员水平的标准之一。自测方法根据所编写程序的特点,自测方法大致有以下几种:第一种是使用仿真工具进行自测。这种方式适用于程序进程需要由其他模块发送的消息触发的情况(暂不可用)。仿真工具应严格按照协议要求发送报文,并处理相应的响应报文。这种方法的优点是可以模拟真实系统来测试代码,功能覆盖比较完整;缺点是仿真工具的编写比较复杂(相当于实现一个完整的功能模块),耗时较多。第二种是使用peer模块进行自检。这种方式适用于两个软件模块的功能耦合性比较强,同时开发的情况。例如,正在开发的模块1的功能A需要触发正在开发的模块2的功能B,模块1和模块2的开发进度是差不多的。这时可以通过模块2向模块1发送消息,功能A和功能B自测。三是手动插入数据或执行命令进行自检。这种方式适用于某个软件模块的功能相对独立的情况。此时,没有其他模块与该模块进行消息交互,也没有编写单独的测试模块。使用手工方式的好处是可以根据程序的特点设置测试用例,代码覆盖率比较高;缺点是数据量大的消息测试难度大,程序性能无法保证。四是在程序中加入测试代码进行自检。也就是说,在编写软件功能代码的同时,在其中加入了测试代码。这种方式的优点是显而易见的,即不需要与其他程序模块进行消息交互,不需要手动插入数据或发送消息,当整个软件模块运行时,测试代码就可以发挥作用。当然,这种方法也有一个缺点,就是编写这些测试代码需要一定的时间,可能会导致代码过于臃肿。在本文的其余部分,我们将使用实际的C代码来说明第四种自检方法的使用。示例程序本文使用的示例程序比较简单。它的作用是每隔一段时间(1分钟)将源目录中满足前缀要求的文件备份(移动)到备份目录。程序(FilesBackup.c)如下:/***************************************************************************版权所有(C)2016,周兆雄。**文件名:FilesBackup.c*文件ID:无*内容概要:备份某个目录下的文件*其他说明:无*当前版本:V1.0*作者:周兆雄*完成日期:20160701*******************************************************************************/#include#include#include#include#include//重新定义数据类型typedefsignedintINT32;typedefunsignedintUINT32;typedefunsignedcharUINT8;//全局变量定义UINT8g_szSourceDir[256]={0};//源文件目录UINT8g_szBackupDir[256]={0};//备份文件目录//函数声明INT32SelectFlies(structdirent*pDir);voidScanDirAndBackup(void);voidSleep(UINT32iCountMs);/*************************************************************************功能说明:主要功能*输入参数:无*输出参数:无*返回值:0-执行完成*其他说明:无*修改日期版本号修改内容修改*------------------------------------------------------------*20160701V1.0周兆雄已创建**********************************************************************/INT32main(void){INT32iRetValue=0;//获取源文件目录snprintf(g_szSourceDir,sizeof(g_szSourceDir)-1,"%s/zhouzx/TestDir/SourceDir",getenv("主页"));//获取备份文件的目录snprintf(g_szBackupDir,sizeof(g_szBackupDir)-1,"%s/zhouzx/TestDir/BackupDir",getenv("HOME"));//调用函数执行文件备份while(1){ScanDirAndBackup();Sleep(60*1000);//每分钟执行一次文件备份}return0;}/*******************************************************************************功能描述:根据前缀和后缀选择文件*输入参数:dir-目录*输出参数:无*返回值:0-失败1-成功*其他说明:无*修改日期版本号修改按修改内容*------------------------------------------------------------------*20160701V1.0ZhouZhaoxiong创建*******************************************************************************/INT32SelectFlies(structdirent*pDir){INT32iSelectResult=0;UINT8szFilePrefix[10]={0};//源文件的前缀if(pDir==NULL){printf("SelectFlies:inputparameterisNULL!\n");return0;}//匹配文件前缀和后缀strncpy(szFilePrefix,"File_",strlen("File_"));iSelectResult=(strncmp(pDir->d_name,szFilePrefix,strlen(szFilePrefix))==0);if(iSelectResult==1)//查找匹配前缀文件{return1;}else{return0;}}/****************************************************************************功能描述:扫描目录和备份文件*输入参数:无*输出参数:无*返回值:无*其他说明:无*修改日期版本号修改人修改内容*---------------------------------------------------------------------*20160701V1.0ZhouZhaoxiong创建*****************************************************************************/voidScanDirAndBackup(void){INT32iScanDirRet=0;UINT32iFileIdx=0;UINT8szScanedFile[512]={0};UINT8szCmdBuf[256]={0};structdirent**ppDirEnt=NULL;iScanDirRet=scandir(g_szSourceDir,&ppselectFirEnt,,alphasort);if(iScanDirRet<0)//扫描目录错误{printf("ScanDirAndBackup:execscandirfailed,path=%s\n",g_szSourceDir);return;}elseif(iScanDirRet==0)//没有fileinthedirectory{printf("ScanDirAndBackup:nosatisfiedfileindirectory%s\n",g_szSourceDir);return;}else//移动符合条件的文件到备份目录{for(iFileIdx=0;iFileIdxd_name);memset(szCmdBuf,0x00,sizeof(szCmdBuf));snprintf(szCmdBuf,sizeof(szCmdBuf)-1,"mv%s%s",szScanedFile,g_szBackupDir);系统(szCmdBuf);printf("ScanDirAndBackup:now,%s\n",szCmdBuf);}}printf("ScanDirAndBackup:thistime,totallymoved%dfile(s)to%s\n",iScanDirRet,g_szBackupDir);return;}/*********************************************************************功能说明:程序休眠*输入参数:iCountMs-休眠时间(单位:ms)*输出参数:无*返回值:无*其他说明:无*修改日期,版本号,修改人,修改内容*--------------------------------------------------------------*20160701V1.0ZhouZhaoxiong创建******************************************************************************/voidSleep(UINT32iCountMs){structtimevalt_timeout={0};if(iCountMs<1000){t_timeout.tv_sec=0;t_timeout.tv_usec=iCountMs*1000;}else{t_timeout.tv_sec=iCountMs/1000;t_timeout.tv_usec=(iCountMs%1000)*1000;}选择(0,NULL,NULL,NULL,&t_timeout);//调用select函数阻塞程序}亲添加测试代码后的gram添加测试代码的基本思路是在扫描源文件目录之前生成目录下的文件,相当于手动把源目录下的文件放上去添加后的程序代码如下:/******************************************************************************版权所有(C)2016,周兆雄。**文件名:FilesBackup.c*文件ID:无*内容概要:备份某个目录下的文件*其他说明:无*当前版本:V1.0*作者:周兆雄*完成日期:20160701*******************************************************************************/#include#include#include#include#include//重新定义数据类型typedefsignedintINT32;typedefunsignedintUINT32;typedefunsignedcharUINT8;//全局变量定义UINT8g_szSourceDir[256]={0};//源文件目录UINT8g_szBackupDir[256]={0};//备份文件目录//函数声明INT32SelectFlies(structdirent*pDir);voidScanDirAndBackup(void);voidSleep(UINT32iCountMs);voidCreateTestFile(void);/*********************************************************************功能说明:主函数*输入参数:无*输出参数:无*返回值:0-执行完成*其他说明:无*修改日期,版本号,被修改者修改意图*--------------------------------------------------------------*20160701V1.0周兆雄创建********************************************************************/INT32main(void){INT32iRetValue=0;//获取源文件目录snprintf(g_szSourceDir,sizeof(g_szSourceDir)-1,"%s/zhouzx/TestDir/SourceDir",getenv("HOME"));//获取备份文件的目录snprintf(g_szBackupDir,sizeof(g_szBackupDir)-1,"%s/zhouzx/TestDir/BackupDir",getenv("HOME"));//调用函数执行文件的备份while(1){//------------//先在源目录下创建测试文件CreateTestFile();//-------------ScanDirAndBackup();Sleep(60*1000);//每分钟执行一次文件备份}return0;}/*****************************************************************************功能描述:根据前缀和后缀选择文件*输入参数:dir-目录*输出参数:无*返回值:0-失败1-成功*其他说明:无*修改日期版本号修改者修改内容*-----------------------------------------------------------------*20160701V1.0ZhouZhaoxiong创建*******************************************************************************/INT32SelectFlies(structdirent*pDir){INT32iSelectResult=0;UINT8szFilePrefix[10]={0};//源文件前缀if(pDir==NULL){printf("SelectFlies:inputparameterisNULL!\n");return0;}//匹配文件前后缀strncpy(szFilePrefix,"File_",strlen("File_"));iSelectResult=(strncmp(pDir->d_name,szFilePrefix,strlen(szFilePrefix))==0);if(iSelectResult==1)//查找到匹配前缀{return1;}else{return0;}}/*********************************的文件*****************************************功能说明:扫描目录和备份文件*输入参数:无*输出参数:无*返回值:无*其他说明:无*修改日期,版本号,修改人,修改内容*----------------------------------------------------------------*20160701V1.0ZhouZhaoxion创建了**************************************************************************/voidScanDirAndBackup(无效){INT32iScanDirRet=0;UINT32iFileIdx=0;UINT8szScanedFile[512]={0};UINT8szCmdBuf[256]={0};structdirent**ppDirEnt=NULL;iScanDirRet=scandir(g_szSourceDir,&ppDirEnt,SelectFlies,alphasort);if(iScanDirRet<0)//扫描目录错误{printf("ScanDirAndBackup:execscandirfailed,path=%s\n",g_szSourceDir);return;}elseif(iScanDirRet==0)//目录下没有文件{printf("ScanDirAndBackup:nosatisfiedfileindirectory%s\n",g_szSourceDir);return;}else//Move将满足条件的文件复制到备份目录{for(iFileIdx=0;iFileIdxd_name);memset(szCmdBuf,0x00,sizeof(szCmdBuf));snprintf(szCmdBuf,sizeof(szCmdBuf)-1,"mv%s%s",szScanedFile,g_szBackupDir);system(szCmdBuf);printf("ScanDirAndBackup:now,%s\n",szCmdBuf);}}printf("ScanDirAndBackup:这次,totallymoved%dfile(s)to%s\n",iScanDirRet,g_szBackupDir);返回;}/*****************************************************************************函数说明:程序睡眠*输入参数:iCountMs-睡眠时间(单位:ms)*输出参数:无*返回取值:无*其他说明:无*修改日期版本号修改人修改内容*----------------------------------------------------------------------*20160701V1.0ZhouZhaoxiong创建**************************************************************************/voidSleep(UINT32iCountMs){structtimevalt_timeout={0};if(iCountMs<1000){t_timeout.tv_sec=0;t_timeout.tv_usec=iCountMs*1000;}else{t_timeout.tv_sec=iCountMs/1000;t_timeout.tv_usec=(iCountMs%1000)*1000;}select(0,NULL,NULL,NULL,&t_timeout);//调用select函数阻塞程序}/***************************************************************************功能描述:创建本地测试文件*输入参数:无*输出参数:无*返回值:无*其他说明:每轮创建的测试文件个数加1,达到1000个后从1开始*修改日期,版本号,修改人,修改内容*----------------------------------------------------------------*20160701V1.0ZhouZhaoxion创建******************************************************************************/voidCreateTestFile(void){UINT32iFileIdx=0;UINT8szFileName[500]={0};FILE*fp=NULL;staticUINT32s_iFileNo=0;s_iFileNo++;if(s_iFileNo>1000){s_iFileNo=0;}for(iFileIdx=0;iFileIdx