【IT168 技术文章】
一、实例
在《CPPUNIT基本原理》中举了一个简单的例子,在这个实例的基础上,另外写了一个稍微复杂的例子用作 cppunit的测试
这个实例包含一个Write2File cpp,一个Write2File h文件,功能是实现从一个文件复制内容到另一个文件。具体实现如下:
Write2File.cpp的代码:
#include "Write2File.h"
Write2File::Write2File()
{
}
Write2File::~Write2File()
{
}
int Write2File::Process() //主过程
{
ReadCfgFile( );
if( ReadFileSrc() )
{
return -1;
}
if( WriteFileOut() )
{
return -1;
}
return 0;
}
int Write2File::ReadCfgFile() //这个函数本来是想实现从配置文件中获取输出目录和输出目录的,后来简化了这段代码,直接将路径赋值给变量了。
{
strcpy( SrcPath , m_srcp );
strcpy( OutPath , m_outp );
return 0;
}
int Write2File::ReadFileSrc() //读取源文件的内容
{
FILE *fp = NULL;
memset( SrcFilename , 0 ,sizeof( SrcFilename ) );
sprintf( SrcFilename , "%s/test_src.txt" , SrcPath );
if( ( fp = fopen( SrcFilename , "r" ) ) == NULL )
{
printf( "Open srcfile error :%s\n" , SrcFilename );
return -1;
}
fnum = stat(SrcFilename,&statbuf);
if( fnum < 0 )
{
printf("there need size of file\n");
}
fnum = statbuf.st_size; //源文件的大小
fread( m_Buf , statbuf.st_size, 1 , fp );
fclose( fp );
return 0;
}
int Write2File::WriteFileOut() //将读取的内容输入到输出文件
{
FILE *fp = NULL;
memset( OutFilename , 0 , sizeof(OutFilename ) );
sprintf( OutFilename , "%s/test_out.txt", OutPath );
if( access(OutFilename , F_OK) == 0 ) unlink( OutFilename );
if( ( fp = fopen(OutFilename , "a+") ) == NULL )
{
printf("Read file %s error!\n",OutFilename );
return -1;
}
fwrite( m_Buf , statbuf.st_size , 1 , fp );
fclose( fp );
return 0;
}
int main(int argc , const char **argv)
{
Write2File writefile;
if( argc!=3 )
{
printf( "ERROR,Example: Write2File srcpath outpath \n" );
return -1;
}
m_argc = argc;
strcpy( m_srcp , argv[1] );
strcpy( m_outp , argv[2] );
//m_srcp = argv;
writefile.Process();
return 0;
}
Write2File.h的代码:
#include <stdlib.h>
#include <math.h>
#include <iostream.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sstream>
class Write2File
{
public:
Write2File();
~Write2File();
public:
char m_Buf[m_BufSize];
//protected:
int ReadCfgFile();
int Process();
int ReadFileSrc();
int WriteFileOut();
char SrcPath[256];
char OutPath[256];
char SrcFilename[256];
char OutFilename[256];
char Logfile[256];
char Logfilepath[256];
char Logfilename[256];
struct stat statbuf;
int fnum;
};
int m_argc;
char m_srcp[256];
char m_outp[256];
class W2File_Test:public CPPUNIT_NS::TestCase
{
CPPUNIT_TEST_SUITE(W2File_Test);
CPPUNIT_TEST(testw2file);
CPPUNIT_TEST_SUITE_END();
public:
void setUp(void);
void tearDown(void);
char SrcPath[256];
protected:
int t_argc ;
const char *t_argv[3];
void testw2file(void);
int f_num;
struct stat statbuf;
};
CPPUNIT_TEST_SUITE_REGISTRATION(W2File_Test);
testw2file.cpp代码如下:
#include "testw2file.h"
void W2File_Test::setUp(void)
{
t_argc = 3;
t_argv[0]="1";
t_argv[1]="/cxcs04/_hl/study/cppunit/testw2file/src";
t_argv[2]="/cxcs04/_hl/study/cppunit/testw2file/src";
}
void W2File_Test::tearDown(void)
{
}
void W2File_Test::testw2file(void)
{
int i;
FILE *fp_out=NULL;
Write2File W2file;
char t_outfile[256];
sprintf( t_outfile , "%s/test_out.txt" , t_argv[1] );
W2file.ReadCfgFile(t_argc , t_argv );
fp_out = fopen(t_outfile , "r");
stat( t_outfile , &statbuf );
f_num = statbuf.st_size; //测试代码获取输出文件的真实大小
printf( "outfile size =%d , srcfile size =%d\n" , f_num , W2file.fnum ); //将代码中获取的输出文件的真实大小和源代码中源文件的大小作对比(即预期值)
CPPUNIT_ASSERT( f_num == W2file.fnum ); //判断两个值的大小,如果一致这个用例就是成功的。
}
如果是在unix环境下,可以写makefile文件完成程序的编译,在此顺便把我的makefile文件也贴出来:
CPP =g++ -g
INCL = -I/mylib/include
LIBS =-L/mylib/lib -lcppunit
SYSLIB = -ldl
PROGRAMS = testw2file
OBJS =main.o testw2file.o
testw2file:${OBJS}
$(CPP) $(CPPFLAG) -o $@ ${OBJS} $(LIBS) ${SYSLIB} ${INCL}
clean:
rm *.o testw2file
二、总结
在网上有不少CPPUNIT的资料,不知道最初的出处在哪里,有一些看了也不是特别清楚要怎么去使用cppunit,实例也不一定就能真正运行起来(当然这份资料也是借鉴了很多网上同行的资料)。为了让入门者更容易上手,在这里班门弄匠地总结一下自己接触CPPUNIT的心得,上面也附了一两个实例,仅是互相学习的意思。
1 CPPUNIT其实是相当于一个框架,我们设计好了测试的方法、预期值后,将源代码放到这个框架中去执行,以检查源代码的输出是否跟预期值是相符的。
2不需要将源代码贴到测试代码中去,一般建议保持源代码和测试代码的独立性
3 对于预期值需要根据源代码的实际情况去设置,比如如果我要判断一个复制文件的函数执行是否成功,可能先要在测试代码中实现获取复制文件的大小,再将这个大小和源文件进行对比,如果一致,说明这个函数执行是成功的。因此,如何判断某个函数的执行是否成功,这个预期值应该取什么值以及要如何获得这个预期值,都是需要思考的,而且在测试代码中的实现有可能也会比较复杂。不过只要一次实现后,以后的修改就比较小了。
4对于有桩函数或者是驱动函数的函数,需要在测试代码中实现先将被测源代码中实现桩函数或驱动函数的功能。比如被测函数需要用到一个变量,则需要在测试代码中先给这个变量赋值,或者是被测函数需要桩函数先实现某个功能或达到某个条件,则需要在测试代码中先将这个前提条件满足。
5 如果涉及数据库的代码,建议是不要用CPPUNIT来实现,其实直接用功能测试来检查结果会更快捷.