现在的位置: 首页 > 综合 > 正文

在VS2005下搭建和使用CppUnit

2013年10月21日 ⁄ 综合 ⁄ 共 4899字 ⁄ 字号 评论关闭

编译安装CPPUnit:
解压CPPUnit,里面的INSTALL-WIN32.txt说明了如何编译CPPUnit和它的实例,简单的讲步骤如下:
打开src/CppUnitLibraries.dsw,如果是VC 7及以上版本,会有一个对话框询问是否将工程转换成更高版本,选择“Yes to all”进行转换;
打开“Build”菜单,选择“Batch Build...”,弹出“Batch Build...”对话框后点击“Select All”,然后Build。
链接过程中会报错:
error C3505: cannot load type library '{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}'
出错的文件是:src/msvc6/testrunner/MsDevCallerListCtrl.cpp。这是由于使用VC 8.0编译的缘故,需要修改一下它的源码,打开该文件,找到出错行(#67),将其替换为:
#if _MSC_VER >= 1400    // VC++ 8 or more
//The following #import imports EnvDTE based on its LIBID.
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
//The following #import imports EnvDTE80 based on its LIBID.
#import "libid:1A31287A-4D7D-413e-8E32-3B374931BD89" version("8.0") lcid("0") raw_interfaces_only named_guids
#else // vc7
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids
#endif

如此一来,就将VC 7和8分开处理了。另外还有一个错误:
error C1189: #error :  This add-in is for VC++ 6.0 only
发生这个错误的是工程“DSPlugIn”,这只是个插件,没有也不影响CPPUnit的使用,因此可以无视这条错误。再次编译,可以从lib文件夹中找到所有的静态库文件及动态库文件,将include和lib文件夹加入到VC++的环境中,打开:Tools|Options|Projects and Solutions|VC++ Directories,将这两个文件夹的路径分别加入到Include files和Library files中。最好再将lib文件夹加入到系统环境变量PATH中,这样就不用再将其中的动态链接库拷到工程目录下而直接运行单元测试了。至此,CPPUnit的编译安装就完成了。

使用CPPUnit:
CPPUnit有GUI和文本两种测试模式,这里以文本模式为例:
新建一个控制台静态库工程,其头文件内容如下:
#ifndef __UNIT_H__
#define __UNIT_H__

//简单计算类,被用于单元测试
class Compute
{
public:
 int add(int a, int b); //加法计算
 int dec(int a, int b); //减法计算
 int mul(int a, int b); //乘法计算
};
#endif

这个简单的类实现了整数的加减、乘三种基本运算,其实现文件内容如下:
#include "unit.h"

int Compute::add(int a, int b)
{
 return (a + b);
}
int Compute::dec(int a, int b)
{
 return (a - b);
}
int Compute::mul(int a, int b)
{
 return (a * b);
}

编译得到.lib文件,这就是待测模块,然后再创建单元测试工程:
创建一个控制台可执行文件工程,增加一个测试用例——CppUnit将所有的单元测试按照树的结构来表示。最小的测试单元,称为TestMethod(测试方法),而多个相关的测试方法又可以组成一个TestCase(测试用例)。多个测试用例又组成TestSuite(测试组)。测试包互相嵌套在一起,就形成了上面我们看到的树结构。我们可以选择其中任意的树节点来进行单元测试,如下图所示:

而一个测试用例(TestCase)以一个类的形式体现,以下是测试用例的头文件:
#ifndef __TESTCASE_H__
#define __TESTCASE_H__

#include "cppunit/extensions/HelperMacros.h" //为了使用辅助宏
class ComputeTestCase : public CppUnit::TestCase //继承CppUnit的测试用例类
{
 //建立一个单元测试组
 CPPUNIT_TEST_SUITE(ComputeTestCase);
 //以下多个测试方法组成测试用例(TestCase),测试用例从属于一个测试组(TestSuite)
 CPPUNIT_TEST(test_add);
 CPPUNIT_TEST(test_dec);
 CPPUNIT_TEST(test_mul);
 CPPUNIT_TEST_SUITE_END();
private:
 int a_, b_;
public:
 //以下三个成员函数为测试方法(TestMethod)
 void test_add(); //测试加法运算
 void test_dec(); //测试减法运算
 void test_mul(); //测试乘法运算
 virtual void setUp(); //单元测试初始化函数
 virtual void tearDown();//单元测试结束清理函数
};

#define SUITE_NAME "TEST_EXAMPLE" //测试组名称
#endif

测试用例的实现如下:
#include "stdafx.h"
#include "testcase.h"
#include "../cppunit/unit.h" // 包含待测工程头文件

// 注册一个命名测试组
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ComputeTestCase, std::string(SUITE_NAME));

// 初始化测试
void ComputeTestCase::setUp()
{
 a_ = 70;
 b_ = 30;
}

// 测试结束后的清理
void ComputeTestCase::tearDown()
{
 //由于没有涉及到内存分配等操作,因此不需要清理
}

void ComputeTestCase::test_add()
{
 Compute test; // 创建一个计算类对象
 int ret = test.add(a_, b_); // 调用计算类对象的加法成员函数
 CPPUNIT_ASSERT_EQUAL(100, ret); // 测执行结果是否符合预期值
}

void ComputeTestCase::test_dec()
{
 Compute test; // 创建一个计算类对象
 int ret = test.dec(a_, b_); // 调用计算类对象的减法成员函数
 CPPUNIT_ASSERT(40 == ret); // 测试执行结果是否符合预期值
}

void ComputeTestCase::test_mul()
{
 Compute test; // 创建一个计算类对象
 int ret = test.mul(a_, b_); // 调用计算类对象的乘法成员函数
 //检查执行结果是否符合预期值,不符合时打印自定义消息
 CPPUNIT_ASSERT_EQUAL_MESSAGE(std::string("test mul failed!"), ret, 0);
}

 

可以看到,在三个测试方法(TestMethod)中创建了待测库中的Compute类对象,并调用该对象提供的运算方法,最后将结果进行CPPUnit断言,CPPUnit断言宏有以下形式:
CPPUNIT_ASSERT(condition):判断condition的值是否为真,如果为假则生成错误信息。CPPUNIT_ASSERT_MESSAGE(message, condition):与CPPUNIT_ASSERT类似,但结果为假时报告messsage信息。
CPPUNIT_FAIL(message):直接报告messsage错误信息。
CPPUNIT_ASSERT_EQUAL(expected, actual):判断expected和actual的值是否相等,如果不等输出错误信息。
CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual):与CPPUNIT_ASSERT_EQUAL类似,但断言失败时输出message信息。CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta):判断expected与actual的偏差是否小于delta,用于浮点数比较。
CPPUNIT_ASSERT_THROW(expression, ExceptionType):判断执行表达式expression后是否抛出ExceptionType异常。
CPPUNIT_ASSERT_NO_THROW(expression):断言执行表达式expression后无异常抛出。
这些断言宏的使用方法很简单,这里不作敷述。再回到上面的代码,可以看到里面有setUp和tearDown两个虚方法,重写它们以针对测试用例进行初始化及清理工作。最后还有一个包含主函数main()的Cpp文件:
#include "stdafx.h"
#include "testcase.h"

// 包含必要的头文件
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestRunner.h>

int _tmain(int argc, _TCHAR* argv[])
{
     CppUnit::TestResult r;
     CppUnit::TestResultCollector rc;
     r.addListener(&rc); // 准备好结果收集器
     CppUnit::TestRunner runner; // 定义执行实体
  // 往执行实体中注册测试组(TestSuite)  runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(std::string(SUITE_NAME)).makeTest());
     runner.run(r); // 运行测试
     CppUnit::TextOutputter o(&rc, std::cout);
     o.write(); // 将结果输出到标准输出流
    return rc.wasSuccessful() ? 0 : -1;
}

直接编译会出错,还要往工程中加入compute.lib testrunnerd.lib cppunitd.lib三个库文件,其中第一个为待测库,后两个是CPPUnit的静态库。得到可执行文件后运行结果如下:

可以看到,此次测试运行了3个单元,其中有一个失败,失败信息比如文件名、行号、方法名也被详细打印出来了。至此,完成了一次简单的单元测试。

 

最后,可以在本压缩包中获得两个实例,一个与本文配套,另一个演示了如何进行基于GUI的单元测试。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dk123/archive/2008/07/18/2673336.aspx

抱歉!评论已关闭.