UnitTest
2013年5月20日
1 单元测试
定义:基于某种单元测试框架编写的测试代码,用于测试特定函数或类,验证其逻辑行为的假设,具有全自动,可信赖,可维护,可读性强、运行快速的特点。
单元测试属性白盒测试和结构性测试,一般由开发人员进行。主要由收费的CPPTest和开源的CPPUnit。
单元测试框架主要进行单元测试管理和自动化测试。
1.1 测试的原则
任何包含逻辑的代码,都应该被测试。
每一个目标项目建立测试项目,每一个目标类建立一个测试类,每一个目标方法建立至少一个测试方法。
1.2 测试的要求
测试不能影响目标程序。
1.3 测试用例命名
参考:http://book.51cto.com/art/201111/301856.htm 《单元测试的艺术》
1.4 测试构造与析构函数
setUp():每次测试函数执行前执行,用于测试构造。
tearDown():每次测试函数执行结束后执行,用于测试析构。
如果要测试一个类的功能,可以将类设置为数据成员,在setUp()中进行初始化,在tearDown()中进入释放。
2 TDD:测试驱动开发
定义:使用测试驱动开发。
步骤:
编写测试代码,如果失败,则进行生产代码开发,测试通过后,进行重构或者开始新的测试。
3 CppUnit(推荐)
参考:http://www.cnblogs.com/eric_lgf/archive/2009/10/10/1580330.html
CPPUnit移植于JUnit,源于极限编程思想。
CppUnit中的测试方法要求所有的测试函数都返回void,不接受参数。
3.1 下载
SVN:https://cppunit.svn.sourceforge.net/svnroot/cppunit/trunk/cppunit/
Code:http://sourceforge.net/projects/cppunit/
目前版本是1.12.1
3.2 编译
3.2.1 转换
解压后用VS打开src下的.dsw(如果不是vc6,需要转换,默认转换就可以了)。
3.2.2 编译
在VS2010下,会有6个工程,其中CPPUnit为静态库,CPPUnit_Dll为动态库。其它的都是插件,如果在Console下使用,则只编译CPPUnit(lib类型)就可以了。如果要在MFC下使用,还要编辑TestRunner(dll类型),用于图形化显示测试结果。
3.2.2.1 修改输出文件名
CPPUnit在编译时会有输出文件与期望不同的警告并报错,这里根据提示改为工程名+d。
TestRunner在编译时也存在输出名称的警告,这里也根据提示改为工程名+d。
3.2.2.2 修改MSC版本
还会有一个错误,在src\msvc6\testrunner\MsDevCallerListCtrl.cpp下67行有个MSC的版本,将7改为8。
3.2.2.3 修改字符集
MFC默认使用Unicode,而CPPUnit使用Mulitbyte,在新建测试项目时,如果字符集不同,会报错。这里在编译的时候选择字符集为Unicode,可以避免每次新建测试项目时设置字符集。
3.3 在目标工程中测试
在目标工程中测试会导致修改目标工程,不符合测试不影响目标的要求,这里仅用来检测CppUnit的可用性。
3.3.1 构建测试类
3.3.1.1 添加库及头文件
测试类用于测试目标类的服务,派生于CPPUNIT_NS::TestFixture,用于生成测试套件(SUITE)。所以需要包含目标类头文件和cppunit.lib库文件。
3.3.1.2 添加测试套件
构建测试类时,首先要添加测试套件,使用宏来定义,这里需要一个定义宏的头文件cppunit\extensions\helpmacros.h。
测试套件格式
CPPUNIT_TEST_SUITE(测试类名称);
CPPUNIT_TEST(测试函数名);
……
CPPUNIT_TEST_SUITE_END();
3.3.1.3 实现测试构造、析构函数(setUp(),tearDown())
setUp():每次测试函数执行前执行,用于测试构造。
tearDown():每次测试函数执行结束后执行,用于测试析构。
3.3.2 实现测试函数
实现每个测试函数,并添加断言。
3.3.3 执行测试
3.3.3.1 构建测试执行者
测试执行者在CPPUnit中由类CppUnit::TextUi::TestRunner实现。
声明位于cppunit/ui/text/testrunner.h中。
首先生成一个测试执行者TestRunner的对象。
3.3.3.2 向执行者添加测试套件
向测试执行者中添加测试套件。
objTestRunner.addTest(测试类::suite());
3.3.3.3 输出
如果需要将测试结果输出到文件中,可以在这里设置输出文件,并输出。默认情况下输出到命令行窗口。
输出文件头文件:cppunit/compileroutputter.h
a) 生成输出文件
Std::ofstream(文件路径);
b) 生成输出对象
CppUnit::CompilerOutputter*pOutputter = CppUnit::CompilerOutputter::defaultOutputter(&result,输出文件);
c) 将输出对象的指针设置到测试执行者对象。
objTestRunner.setOutputter(pOutputter);
3.3.3.4 执行测试
调用测试执行函数,就可以进行自动测试了。
Enjoy!
3.3.4 示例
//calctests.h
//用于测试CCalc类
#pragma once
#include "Calc.h"
#include <cppunit\extensions\HelperMacros.h>
#pragma comment(lib,"cppunitd.lib")
class CCalcTests:public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(CCalcTests);
CPPUNIT_TEST(Sum_ValidAdd_Return0);
CPPUNIT_TEST(Sum_ValidAdd_Return5);
CPPUNIT_TEST_SUITE_END();
public:
CCalcTests(void);
~CCalcTests(void);
private:
CCalc* m_pCCalc;
public:
virtualvoid setUp(void);
virtualvoid tearDown(void);
voidSum_ValidAdd_Return0(void);
voidSum_ValidAdd_Return5(void);
};