Chinaunix首页 | 论坛 | 博客
  • 博客访问: 419271
  • 博文数量: 79
  • 博客积分: 2886
  • 博客等级: 少校
  • 技术积分: 968
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-16 10:33
文章分类

全部博文(79)

文章存档

2013年(7)

2012年(17)

2011年(28)

2010年(25)

2009年(1)

2008年(1)

我的朋友

分类: C/C++

2011-03-18 15:09:26

一、   CppUnit简介

 

ACppUnit源代码组成

CppUnit测试框架的源代码可以到 上下载,当前最高版本为cppunit-1.12.0.tar.gz。下载解压后,你将看到如下文件夹:

图一

主要的文件夹有:

  • config:配置文件;
  • contribcontribution,其他人贡献的外围代码;
  • doc: CppUnit的说明文档。另外,代码的根目录,还有三个说明文档,分别是INSTALLINSTALL-unixINSTALL-WIN32.txt
  • examples: CpppUnit提供的例子,也是对CppUnit自身的测试,通过它可以学习如何使用CppUnit测试框架进行开发;
  • include: CppUnit头文件;
  • src: CppUnit源代码目录;
  • lib:存放编译好的库;

B初识CppUnit测试环境

解压源代码包(cppunit-1.12.0.tar.gz)后,您一定急着想看看CppUnit到底是个什么样?下面我们就来揭开CppUnit的神秘面纱:

    1、进入example文件夹,用VC打开examples.dsw。我们先来看看CppUnit自带的测试例子。这些例子都是针对CppUnit自身的单元测试集,一方面这是CppUnit作者开发CppUnit框架过程中写的测试用例,另一方面,我们可以通过这些例子来学习如何在我们自己的工程中添加测试用例。

    2、将CppUnitTestApp工程设为Active ProjectWin32 Debug),编译后运行,则可以看到CppUnit的基于GUI方式进行单元测试TestRunner的界面。点击“Run”,将会看到如图二所示界面:

图二

这是一个针对CppUnit的单元测试结果,它表明刚才我们做了11个测试,全部通过。

点击“Browse”,我们还可以选择想要进行的单元测试,如图三:

图三

CppUnit将所有的单元测试按照树的结构来表示。在CppUnit中,最小的测试单元,称为TestMethod测试方法,而多个相关的测试方法又可以组成一个TestCase测试用例。多个测试用例又组成TestSuite测试包。测试包互相嵌套在一起,就形成了上面我们看到的树结构。我们可以选择其中任意的树节点来进行单元测试。

3、将CppUnitTestMain工程设置为Active ProjectWin32 Debug,编译并运行,我们来看看另一个单元测试的环境,如图

这是一个基于文本方式的单元测试环境。CppUnit提供了几种测试环境,一种基于文本,一种基于GUI,即图

 

4、将HostApp工程设置为Active ProjectWin32 Debug),编译运行。如图五:

这亦是一个对CppUnit自身进行的测试,只不过它向我们演示的是各种失败的测试。在基于GUI的测试环境中,若测试不成功,进度条显示红色,反之则为绿色。从测试结果我们可以看到失败的单元测试名称,引起测试不能通过的原因,以及测试失败的语句所在的文件及所在行数。

二、   CppUnit单元测试环境搭建

 

CppUnit初步了解后,你是否已经磨拳擦掌,准备进行你的测试了?下面我们按照下面的步骤一步步完成我们自己的测试:

 

第一步:编译CppUnit 静态库文件*.lib和动态库文件*.dll:

1、 CppUnitlibdll

 

接下来进行编译工作。进入src文件夹,打开CppUnitLibraries.dsw。点击菜单build-batch build,编译成功的话,生成的库文件将被拷贝到lib目录下。中途或者会有些project编译失败,一般不用管它,我们重点看的是cppunitTestRunner 这两个projectdebugrelease版本。

 

编译通过以后, lib/目录下,会生成若干lib,dll文件, 都以cppunit开头. cppunitd表示debug, cppunit表示release版。

 

CppUnit为我们提供了两套框架库,一个为静态的lib,一个为动态的dllcppunit project:静态libcppunit_dll project:动态dlllib。在开发中我们可以根据实际情况作出选择。

 

你也可以根据需要选择所需的项目进行编译,其中项目cppunit为静态库,cppunit_dll为动态库,生成的库文件为:

·       cppunit.lib:静态库release版;

·       cppunitd.lib:静态库debug版;

·       cppunit_dll.lib:动态库release版;

·       cppunitd_dll.lib:动态库debug版;

 

另外一个需要关注的projectTestRunner,它输出一个dll,提供了一个基于GUI 方式的测试环境,即前面我们提到的两种测试环境之一。我们也需要编译这个project,输出位置亦为lib文件夹。

 

为了方便开发,我们把这些编译出来的libdll拷贝到我们自己建立的一个文件夹中(当然你也可以不这么做),例如D:\Mytest\lib\,同时我们也把CppUnit源代码中include文件夹copy到我们自己的include文件夹下。

 

第二步:建立基于对话框的工程

 

打开VC,在File菜单项下选择New,建立基于dialog的工程。工程名Project name、存放位置Location可以自己决定,其他选项如下:

OK确认后,进入如下界面。选择Dialog based选项,按Finish按钮后,一个空的基于对话框的工程就建立起来了。

 

第三步:添加被测对象CCounter

 

将被测对象所在文件(*.h*.cpp 添加到工程中:

测试代码

 

//-----------------------------------------------------------Counter.h

#if !defined(AFX_COUNTER_H__0A5AD14A_0E78_4976_9A70_A78649112BA5__INCLUDED_)

#define AFX_COUNTER_H__0A5AD14A_0E78_4976_9A70_A78649112BA5__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

// Counter.h : header file

//

#include "Resource.h"

/////////////////////////////////////////////////////////////////////////////

// CCounter dialog

 

class CCounter : public CDialog

{

// Construction

public:

            CCounter(CWnd* pParent = NULL);   // standard constructor

 

// Dialog Data

            //{{AFX_DATA(CCounter)

            enum { IDD = IDD_DIALOG_COUNTER };

            //}}AFX_DATA

 

            int IsCodeLine(CString,int);

// Overrides

            // ClassWizard generated virtual function overrides

            //{{AFX_VIRTUAL(CCounter)

            protected:

            virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

            //}}AFX_VIRTUAL

 

// Implementation

protected:

 

            // Generated message map functions

            //{{AFX_MSG(CCounter)

                        // NOTE: the ClassWizard will add member functions here

            //}}AFX_MSG

            DECLARE_MESSAGE_MAP()

};

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_COUNTER_H__0A5AD14A_0E78_4976_9A70_A78649112BA5__INCLUDED_)

 

//-----------------------------------------------------------Counter.cpp

#include "stdafx.h"

#include "MyTest.h"

#include "Counter.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CCounter dialog

 

 

CCounter::CCounter(CWnd* pParent /*=NULL*/)

            : CDialog(CCounter::IDD, pParent)

{

            //{{AFX_DATA_INIT(CCounter)

                        // NOTE: the ClassWizard will add member initialization here

            //}}AFX_DATA_INIT

}

 

 

void CCounter::DoDataExchange(CDataExchange* pDX)

{

            CDialog::DoDataExchange(pDX);

            //{{AFX_DATA_MAP(CCounter)

                        // NOTE: the ClassWizard will add DDX and DDV calls here

            //}}AFX_DATA_MAP

}

 

 

BEGIN_MESSAGE_MAP(CCounter, CDialog)

            //{{AFX_MSG_MAP(CCounter)

                        // NOTE: the ClassWizard will add message map macros here

            //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CCounter message handlers

 

int CCounter::IsCodeLine(CString a,int b)

{

            return 0;

}

第四步:屏蔽工程对话框

 

在工程MyTest.cpp文件中(本指南中为该文件名,实际学习时根据自己的工程文件名而变),找到BOOL CMyTestApp::InitInstance()方法,将如下蓝色代码注释掉:

BOOL CMyTestApp::InitInstance()

{

            AfxEnableControlContainer();

 

            // Standard initialization

            // If you are not using these features and wish to reduce the size

            //  of your final executable, you should remove from the following

            //  the specific initialization routines you do not need.

 

#ifdef _AFXDLL

            Enable3dControls();                             // Call this when using MFC in a shared DLL

#else

            Enable3dControlsStatic();        // Call this when linking to MFC statically

#endif

 

/*

            CMyTestDlg dlg;

            m_pMainWnd = &dlg;

            int nResponse = dlg.DoModal();

            if (nResponse == IDOK)

            {

                        // TODO: Place code here to handle when the dialog is

                        //  dismissed with OK

            }

            else if (nResponse == IDCANCEL)

            {

                        // TODO: Place code here to handle when the dialog is

                        //  dismissed with Cancel

            }

*/

 

            // Since the dialog has been closed, return FALSE so that we exit the

            //  application, rather than start the application's message pump.

            return FALSE;

}

 

由于我们希望这个Project运行后显示的是图2这样的CppUnit自带的界面,所以我们需要在Instance()中屏蔽掉原有的对话框(蓝色部分注释掉),代之以CppUnitGUI

 

第五步:实现CppUnit测试执行器,并将测试工厂添加到测试执行器中。

 

A、在BOOL CMyTestApp::InitInstance()中,添加如下红色代码:

 

BOOL CMyTestApp::InitInstance()

{

            AfxEnableControlContainer();

 

            // Standard initialization

            // If you are not using these features and wish to reduce the size

            //  of your final executable, you should remove from the following

            //  the specific initialization routines you do not need.

 

#ifdef _AFXDLL

            Enable3dControls();                             // Call this when using MFC in a shared DLL

#else

            Enable3dControlsStatic();        // Call this when linking to MFC statically

#endif

 

            //添加CppUnitMFC类型的测试执行器

            CppUnit::MfcUi::TestRunner runner;

 

            //为被测试类(这里是CCounter)定义一个测试工厂(这里取名叫CounterTest):

            CppUnit::TestFactoryRegistry ®istry

                          = CppUnit::TestFactoryRegistry::getRegistry("CounterTest");

 

            //并将工厂添加到测试执行器中

    runner.addTest( registry.makeTest() );

 

            //运行执行器,显示执行器GUI界面

            runner.run();

 

            /*

            CMyTestDlg dlg;

            m_pMainWnd = &dlg;

            int nResponse = dlg.DoModal();

            if (nResponse == IDOK)

            {

                        // TODO: Place code here to handle when the dialog is

                        //  dismissed with OK

            }

            else if (nResponse == IDCANCEL)

            {

                        // TODO: Place code here to handle when the dialog is

                        //  dismissed with Cancel

            }

            */

 

            // Since the dialog has been closed, return FALSE so that we exit the

            //  application, rather than start the application's message pump.

            return FALSE;

}

 

B、由于BOOL CMyTestApp::InitInstance()中引用了CppUnit的类,所以在文件开始处要添加如下头文件:

 

#include

#include

 

 

第六步:在工程中为被测对象CCounter编写测试类文件CounterTest(可以自定义文件名)

 

按照下面示图加入测试类的*.h文件和*.cpp文件:

 

 

CounterTest.h中的代码如下:

 

#include "cppunit/extensions/HelperMacros.h"

 

class IsCodeLineTest : public CppUnit::TestFixture {

            // 声明一个TestSuite

            CPPUNIT_TEST_SUITE( IsCodeLineTest);

            // 添加测试用例到TestSuite, 定义新的测试用例需要在这儿声明一下

            CPPUNIT_TEST( Counter_UT_IsCodeLine_001);

            // TestSuite声明完成

            CPPUNIT_TEST_SUITE_END();

           

 

public:

            // 定义测试用例

            void Counter_UT_IsCodeLine_001();

           

};

 

CounterTest.cpp中的代码如下(注意头文件要做相应的修改):

#include "stdafx.h"

 

#include "CounterTest.h"

#include ".\counter\counter.h"

 

// 把这个TestSuite注册到名字为"CounterTest"的工厂中

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( IsCodeLineTest,"CounterTest" );

 

#define RET_OK 0

#define RET_FAIL 1

 

void IsCodeLineTest::Counter_UT_IsCodeLine_001()

{

     //定义输入参数

       int bIsComment;

       CString  szFileLine;

 

       //定义期望输出

       int iOkReturn;

       int iOkIsComment;

 

       //定义测试实际输出

       int iResult;

      

       CCounter m_counter;

 

       //用例输入

       szFileLine = "int a";

       bIsComment = false;

 

       //期望输出

       iOkReturn = RET_OK;

       iOkIsComment = false;

 

       //驱动被测函数

       iResult = m_counter.IsCodeLine(szFileLine,bIsComment);

 

       //结果比较

       CPPUNIT_ASSERT_EQUAL(iOkReturn,iResult);

                     CPPUNIT_ASSERT_EQUAL(iOkIsComment,bIsComment);

}

 

 

第七步:加入CppUnit 库文件:

 

CppUnit相关的lib文件和dll文件(cppunitd.lib,cppunitd_dll.lib,testrunnerd.lib)加入到工程中:

 

第八步:设置头文件和lib库文件路径、打开RTTI开关、给dLL库设置环境变量:

 

A、        VCtools/options/directories/include fileslibrary files中设置CppUnit include文件路径和lib文件路径:

 

B、        在你的VC project中打开RTTI开关。具体位置Project Settings/C++/C++ Language

 

  C、为TestRunnerd.dll设置环境变量

 

TestRunnerd.dll为我们提供了基于GUI的测试环境。为了让我们的测试程序能正确的调用它,需要把TestRunnerd.dll拷贝到你的工程路径下。或者最简单的方法是在操作系统的环境变量Path中添TestRunnerd.dll的路径,这样是最省事的。

 

第九步:编译执行。编译连接成功后,运行测试,出现下面的界面,表示测试用例Counter_UT_IsCodeLine_001运行成功.

 

阅读(2929) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~