蓝柚 发表于 2006-4-18 09:54:10

使用CppUnit进行单元测试(详细步骤)

一. CppUnit的安装
      从http://sourceforge.net/projects/cppunit   CppUnit的源码包. CppUnit是开源产品 , 当前最高版本为1.11.0. (在上面的链接所指向的页面上选择 Development Snapshot ).
       下载后,将源码包解压缩到本地硬盘. 以C:为例, 解压到C:\CppUnit-1.11.0 .接下来进行编译工作. 在src/目录下, 将CppUnitLibraries.dsw工程文件用vc 打开.因为这个工程是vc6建的工程, 所以会提示是否将此工程转为vc.net的工程格式. 选择"全是"就行.然后在"生成"菜单中选择"生成解决方案",编译整个工程.
      编译通过以后, 在lib/目录下,会生成若干lib,和dll文件, 都以cppunit开头. cppunitd表示debug版, cppunit表示release版.
      然后配置vc环境:工具菜单->选项->项目->vc++目录, 将C:\cppunit-1.11.0\include加入到vc 的 头文件目录中. 将C:\cppunit-1.11.0\lib 加入到vc的 连接库目录中. 然后将 C:\cppunit-1.11.0\lib路径加入到系统路径中(因为我们的测试程序需要cppunit的dll文件,所以要dll所在路径加入到系统路径(path)变量中, 或者将这些文件拷贝到系统目录中也可以).
二. CppUnit 的使用
       以上工作完成以后,就可以正式使用CppUnit了.
      我们新建一个控制台工程, 假定工程名为TDD1. 假设我们将在这个工程下开发, 那么根据测试驱动的原理,我们需要先建立一个单元测试框架.在CppUnit下, 可以选择控制台方式和UI方式两种表现方案.我们选择UI方式.那么现在在原来工程的基础上,再新增加一个对话框工程. 假设名为:Unit_Test .
      在CppUnit中, 是以TestCase为最小的测试单位, 若干TestCase组成一个TestSuite. 所以我们要先建立一个TestCase.
      新建一个类, 命名为CTestCase , 让其从CppUnit::TestCase派生.为其新增一个方法,假设为 void doTest(); 我们将在这个函数中写入我们的一些测试代码.切记要包含头文件
#include <CppUnit/extensions/HelperMacros.h>

class CTestCase : public CppUnit::TestCase
{
public:
    CTestCase(void);
    ~CTestCase(void);
    void doTest();
};
接下来, 我们要对我们的TestCase进行声明. 声明用到了三个宏.
    CPPUNIT_TEST_SUITE();
    CPPUNIT_TEST();
    CPPUNIT_TEST_SUITE_END();
第一个宏声明一个测试包,第二个宏声明一个测试用例. 现在我们的CTestCase类看上去象这样.
class CTestCase : public CppUnit::TestCase
{
    CPPUNIT_TEST_SUITE(CTestCase);
    CPPUNIT_TEST(doTest);
    CPPUNIT_TEST_SUITE_END();
public:
    CTestCase(void);
    ~CTestCase(void);
    void doTest();
};
接下来,我们要注册我们的测试suite. 使用CPPUNIT_TEST_SUITE_NAMED_REGISTRATION()来注册一个测试suite. 这个宏的第二个参数是我们注册的suite的名字. 在这里我们可以用字符串来代替, 但我们用一个静态函数来返回这个suite的名字.
    //TestCase.h
    static std::string getSuiteName();
    //TestCase.cpp
    std::string CTestCase::getSuiteName()
    {
            return "TDDExample3";
    }
    记得要在TestCase.h中包含 #include <string>
    然后在 TestCase.cpp注册我们的suite.
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CTestCase , CTestCase::getSuiteName() );
   接下来我们写一个注册函数, 使其在运行期生成一个Test.
   
    static CppUnit::Test* getSuite();
    CppUnit::Test* CTestCase::getSuite()
    {
         CppUnit::TestFactoryRegistry& reg =
               CppUnit::TestFactoryRegistry::getRegistry( CTestCase::getSuiteName() );
               return reg.makeTest();
      }
      记住包含头文件:
       #include <cppunit/extensions/TestFactoryRegistry.h>
       最后, 我们的单元测试建立一个UI测试界面.
       我们在CUnit_TestApp::InitInstance()函数中,将原先显示主对话框的代码以下面的代码取代:
    CppUnit::MfcUi::TestRunner runner;
    runner.addTest(CTestCase::getSuite());
    runner.run();
    必须先包含头文件:
#include <cppunit/ui/mfc/TestRunner.h>
#include "TestCase.h"
    到此为止, 我们已经建立好一个简单的单元测试框架. 我们可以在doTest()中加入我们的测试代码,来进行测试了. CppUnit会将测试结果通过一个界面显示出来.
   但此时我们虽然能编译通过,但在连接时会发生错误. 所以将下面两个库加入到工程中. 也可以在TestCase.h 中显式的加入:
#pragma comment(lib,"cppunit.lib")
#pragma comment(lib,"testrunnerd.lib")
   下面是完整的程序清单:
   //TestCase.h
#pragma once
#include <string>
#include <CppUnit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/Asserter.h>
#pragma comment(lib,"cppunit.lib")
#pragma comment(lib,"testrunnerd.lib")
class CTestCase : public CppUnit::TestCase
{
    CPPUNIT_TEST_SUITE(CTestCase);
    CPPUNIT_TEST(doTest);
    CPPUNIT_TEST_SUITE_END();
public:
    static std::string getSuiteName();
    static CppUnit::Test* getSuite();
public:
    CTestCase(void);
    ~CTestCase(void);
    void doTest();
};
//TestCase.Cpp
#include "StdAfx.h"
#include ".\testcase.h"
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CTestCase , CTestCase::getSuiteName() );
CTestCase::CTestCase(void)
{
}
CTestCase::~CTestCase(void)
{
}
void CTestCase::doTest()
{
}

std::string CTestCase::getSuiteName()
{
    return "TDDExample3";
}
CppUnit::Test* CTestCase::getSuite()
{
    CppUnit::TestFactoryRegistry& reg =
      CppUnit::TestFactoryRegistry::getRegistry( CTestCase::getSuiteName() );
    return reg.makeTest();
}
//Unit_Test.cpp
#include <cppunit/ui/mfc/TestRunner.h>
#include "TestCase.h"
BOOL CUnit_TestApp::InitInstance()
{

InitCommonControls();
CWinApp::InitInstance();
AfxEnableControlContainer();
   CppUnit::MfcUi::TestRunner runner;
    runner.addTest(CTestCase::getSuite());
    runner.run();
return FALSE;
}
现在编译,运行, 如图一:

进度条呈现绿色, 表示我们此次测试通过. 事实上我们的doTest是一个空函数,什么代码也没有写,当然能通过了. :)
   下面我们在doTest()中加点代码进去.
      char* p = NULL; p='c';
   这段代码会引起一个访问异常. 看UnitCpp怎么来报告这段代码的错误.
编译,运行如图2:


这时CppUnit会告诉我们dotest出现一个错误. 并提供了错误的一些信息.
          这样我们用CppUnit搭建一个简单单元测试框架.

蓝柚 发表于 2006-4-18 09:56:52

上面程序已经过验证,但也只是简单介绍下框架,希望对大家有些帮助~!

zx116_2000 发表于 2006-4-18 15:02:42

谢谢!
我VC版本是:Visual C++ 2005 Express Edition
可编绎 CppUnit-1.11.0时,编绎失败,
D:\Program Files\Microsoft Visual Studio 8\VC\include\xlocinfo.h(6) : fatal error C1083: Cannot open include file: 'locale.h': No such file or directory TestResultCollector.cpp
这是编绎失败的相关信息~

zixuxuwu 发表于 2006-4-18 20:52:25

找个安装包,把这个文件拷到你的安装目录下。

天生我才 发表于 2006-4-24 08:21:36

谢谢斑竹了

男孩子 发表于 2006-11-7 10:53:49

楼主的文章写得非常棒,可是有一处搞不清楚:
“我们新建一个控制台工程, 假定工程名为TDD1. 假设我们将在这个工程下开发, 那么根据测试驱动的原理,我们需要先建立一个单元测试框架.在CppUnit下, 可以选择控制台方式和UI方式两种表现方案.我们选择UI方式.那么现在在原来工程的基础上,再新增加一个对话框工程. 假设名为:Unit_Test . ”

控制台工程中如何增加一个对话框工程呢?VC学的不好,见笑。

VisualUnit 发表于 2006-11-7 11:05:41

楼主的原意大概是在workspace中增加一个对话框工程,表达稍有点不清,呵呵。
产品工程是TDD1,新建一个测试工程Unit_Test,大概是这意思。

男孩子 发表于 2006-11-8 11:49:18

唉,水平有限,还是不知道怎么弄。
谢谢楼上提醒了,按照你讲的做有些眉目了,但是编译有问题,不知道怎么回事。

VisualUnit 发表于 2006-11-8 12:53:09

to 男孩子

还是用Visual Unit吧,要简单好用高效得多,中文资料齐全,包括视频教程,还有在线技术支持。免费的版本(个人版)也挺好用的,仅自动生成测试代码这一项就至少可以减少百分之七十的测试时间。

很多人以为自动生成测试代码不如手工编写灵活,其实这是误解。因为:
VU生成的测试代码是透明的,需要时可以修改;
VU具有自定义测试功能,这里就是由用户自行编写测试代码的,不过一般的测试是用不上的,主要用于特殊需求如对已编译好的DLL或COM组件的测试;
VU不需要由测试代码来进行测试组织,因此测试代码更简单,简单就意味着灵活;
预期输出是很重要的部分,CPPUNIT是一堆宏,VU只使用一个宏,既简单又灵活,如下面的预期输出都是可以的:
strcmp(str, "abce") == 0//判断两个字符串是否相等
.m_strName.IsEmpty() //用.操作符直接访问成员变量,可以直接调用返回值为布尔类型的函数
ret > 0 || a <0//复合表达式也行
对于第一和第三个例子,CPPUNIT要使用中间变量才行。

至于其他优点,因不具有可比性,我就不说了。我建议您两种都试试,有比较才分得清优劣。

官方网站 http://www.KaileSoft.cn

[ 本帖最后由 VisualUnit 于 2006-11-8 13:01 编辑 ]

男孩子 发表于 2006-11-8 13:28:41

to:VisualUnit
我现在学习CppUnit是公司指定的,没有自主选择的权利。所以还是谢谢你的好意了。

华人天堂 发表于 2006-12-31 09:55:34

我现在在公司学这两个工具,再要我选一个拿来用,我是想用Visual unit的,不用编程,对做测试的我来说,倒是方便的,比楼上那哥们要好点

alina_zh 发表于 2007-3-27 00:01:59

我在安装CPPUnit时,发现一个错误提示:
Error executing c:\windows\system32\cmd.exe

系统目录下cmd.exe是存在的啊~~

不知道这个错误问题大不大,该怎么改呢?

编译设置完后,我建了一个测试环境来试着测一个小程序,可是编译时提示:
F:\ResourceCode\test\test compare\main.cpp(10) : error C2039: 'TextUi' : is not a member of 'CppUnit'
F:\ResourceCode\test\test compare\main.cpp(10) : error C2065: 'TestRunner' : undeclared identifier

这是怎么回事儿呢?与上面提到的安装时的错误有关吗??

changing 发表于 2009-5-26 11:59:12

救救

请问,debug和release的设置分别是什么?

我总出现错误:LINK : fatal error LNK1104: cannot open file "..TDD1\unit_test1\Debug/cppunitd.lib"
Error executing link.exe.
我的设置的project--settings--C/C++页面信息如下:
Output file name: ..\TDD1\unit_test1\Debug/unit_test1.exe
Object/library modules: ..\TDD1\unit_test1\Debug/cppunitd.lib ..\TDD1\unit_test1\Debug/testrunnerd.lib
我的这两个文件已经放在debug目录下了,还是一样出错误!
页: [1]
查看完整版本: 使用CppUnit进行单元测试(详细步骤)