最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

C++Test介绍及使用说明

来源:动视网 责编:小OO 时间:2025-10-02 01:04:58
文档

C++Test介绍及使用说明

1个人意见1.1一个例子对以下的函数(在其提供的例子程序divide_by_zero.cpp中)//calculatessumofspecifiedvaluesintget_sum(int*data,unsignedintsize){//missingcheckingif'data'existsintsum=0;for(inti=0;i
推荐度:
导读1个人意见1.1一个例子对以下的函数(在其提供的例子程序divide_by_zero.cpp中)//calculatessumofspecifiedvaluesintget_sum(int*data,unsignedintsize){//missingcheckingif'data'existsintsum=0;for(inti=0;i
1个人意见

1.1一个例子

对以下的函数(在其提供的例子程序divide_by_zero.cpp中)

// calculates sum of specified values

int get_sum(int *data, unsigned int size) {

    // missing checking if 'data' exists 

    int sum = 0;

for (int i = 0; i < size; i++) {

        sum += data[i];

    }

    return sum;    

}

在VC环境下对其进行动态分析,选择把信息输出到C++Test界面下,可以看到:

可以看到红色的测试用例表示出现异常,绿色的测试用例表示正确。

对第一个红色的测试用例进行分析:

输入值data为空,size为198,很明显data为空,即指针为空,没有对指针进行保护,肯定出异常,在原来的函数中加上一段,如红色所示。

// calculates sum of specified values

int get_sum(int *data, unsigned int size) {

    // missing checking if 'data' exists 

    int sum = 0;

    if ( !data )

       {

        return 0;

       }

for (int i = 0; i < size; i++) {

       sum += data[i]; 

    }

    return sum;    

}

再次分析,可得到如下的结果:

对于AUTO_1_A_2这个测试用例,用鼠标右键可以查看此测试用例,如下图:

可见对于只有一维的数组,却加了4294967265次。这次是SIZE越界。需要保护:

// calculates sum of specified values

int get_sum(int *data, unsigned int size) {

    // missing checking if 'data' exists 

    int sum = 0;

    if ( !data )

       {

        return 0;

       }

for (int i = 0; i < size; i++) {

        sum += data[i];

    }

    return sum;    

}

还有很多问题,例如:I是int类型,而size是unsigned int类型,当size很大时,I就无法跟上它同步大小,sum也可能越界。

另外,也可以设置自己的测试用例,设置预期的结果,进行对算法正确地判断。如下图:

当datat[0]=21474837,size=1,这时候sum肯定=21474837,否则就是算法错误。其实这个测试用例是C++Test自动生成的,怎么样?够强大吧。

1.2个人意见

有人认为:

C++Test速度慢,耗系统资源,测试执行效率低。

我觉得,如果你要马上看到测试结果,最好一个文件一个文件的测试,因为你还要仔细分析测试用例和测试结果。如果你想大规模的对很多文件进行单元测试,最好下班前做好准备,第二天早上来看结果。我对一个VC的工程,856K大小的源程序,46个C文件,用了两个小时。不过也是应该的,因为要生成很多的测试程序、桩程序和测试用例,很麻烦的。

基于消息驱动的,函数之间传递的参数多为消息结构或消息的指针,对于这种类型的函数测试,C++Test的自动生成的测试用例和测试结果都没有实际意义,必须人工编辑测试用例。

我觉得,C++Test主要是对指针的保护、越界,数组的越界,变量的越界等很有用,对于数算等函数,可以明确知道返回值的,可以设置预期的返回值,来检查算法是否正确。对于可以通过以下的7 种类型的值的设置可以判断函数算法的正确也很有用。对于象数据库,可以用对函数来互相测试,例如测试建立一个数据库的函数,可以用写库函数或读库函数来判断是否建立正确。对于象消息的建立、释放等也可以用对函数来互相测试。本来单元测试的目的就是查找一些保护、越界错误,简单的可以通过以下7种来判断的函数的算法正确,代码走读是必不可少的。对于复杂的函数还要靠自己建立驱动程序和桩函数。

C++Test 测试用例可以控制7 种类型的变量条件(取决于被测函数用了多少):

. 参数(Arguments): 函数的入口参数。

. 参数出口条件(Arguments Post): 函数执行完成时入口参数的状态。

. 返回值(Return): 函数的返回值。

. 对象前置条件(Pre Conditions> This): 测试开始前对象的条件。

. 对象后置条件(Post Conditions> This): 测试执行后对象的条件。

. 前置条件(Pre Conditions> Externals): 测试开始前全局变量的条件。

. 后置条件(Post Conditions> Externals): 测试执行后全局变量的条件。

2如何操作C++Test

2.1在VC见面下

选择动态分析按钮,输出结果可以输出到VC的OUTPUT窗口或C++Test界面的窗口。建议输出到C++Test界面的窗口,看到的内容比较直观和多。

2.2在C++Test的界面下

打开一个VC的工程,先Read Symbls,再运行动态分析。察看分析结果,如果有必要可以对一个函数增加一个自己的测试用例进行单独测试。

也可以建立一个测试单元包含几个文件测试,桩函数可以选择是自己原先的函数还是C++Test创建的函数。

以下是一些说明:

3设置自己的测试参数

C++Test 有三种类型的测试参数设置:

通用设置(General):应用于整个C++Test 操作。命令:Settings> Customize。

项目设置(Project): 应用于项目中所有的C++Test 测试。命令:Project> Project Settings。

自动测试设置(Automatic):应用于动态分析测试。命令:Project> Project Test Configuration;

如果要为某个文件、类或方法定制测试参数:在项目树中选择目标符号(如项目、类或方

法),然后用右键或菜单选择Project > File/Class/Method Test Configuration。

自动测试设置由三部分组成:值、类型和测试用例生成。

3.1自动测试设置[值-Value Groups]

这些设置描述在动态分析测试时分配给变量的值一般是如何确定的:

Parent Values:Values are defined only in the parent's context。

Standard Values:在测试参数中预先定义的标准值。

Heuristic Values:在自动生成测试用例时采用“智能参数推测(Smart Argument Guessing)”

技术―――一种内建的专门为测试设计的智能系统,可以根据代码中的上下文关系生成更好

的输入值。具体示例见【自动测试尽可能多的分支和边界条件】。

User Defined Values:用户自定义的特殊值。←自定义值

3.2自动测试设置[类型-Types]

C++Test 在测试每种类型的变量(布尔/字符/整数等)时将要分配的值。你可以使用或禁用某些值,或增加自己的特定值。C++Test 还提供了指定一组值的能力。

【例】设计一组整数值

选择:Types>int>,单击[Add Value],单击[Values’ Range],然后输入你想要的值。

(1)按步长5 定义一组5 个值(-10, -5, 0, 5, 10):

(2)在[-10,10]内随机生成5 个值(可能是-8, 1, 3, 4, 10):

3.3自动测试设置[测试用例生成- Test Case Generation]

控制动态分析测试的测试用例生成:

Max. Count of Generated Test Cases: 对一个被测函数可能生成的最大测试用例的数量。允

许任何大于0 的整数。默认是50个,可以修改。

Max Depth of Field Inspection: 对分层或嵌套的类可能生成的测试用例的最大深度。允许任

何大于0 的整数。有时不很容易确定合适的域检查的最大深度。我们建议你观察一下测试

结果浏览窗,在你的初始测试中包括多少层次的检查,如果你需要更多的检查层次,增加

该值。

Timeout (in seconds) for Test Case Execution: 一个测试用例执行的最长时间(秒数),超过

这个时间,C++Test 将给出一个信息并终止当前测试用例的执行,转到下一个测试用例执

行。允许任何大于0 的整数。

Max. Dynamic Allocation Size: 对于一个给定的变量,当动态分配内存(该变量类型)时,

分配的元素的最大数量。该参数避免分配过量的内存,而你在当前测试时并不需要,例如

数组。允许任何大于0 的整数。

Object Initialization Mode: 你可以自由选择地初始化对象,有三种方法:

1)Use Constructors   ―――使用构造函数,

2)Using Member Wise ―――在成员函数中直接初始化,

3)Use Object Repository ―――使用对象库中保存的自定义对象。可以组合使用这些方法。注意只使用构造函数时,产生的测试用例可能比预期的要少。

Dynamic Analysis Mode for Symbols without Test Cases: Auto-Generate Test Cases: 控制是否要自动生成测试用例。

4自动执行白盒测试

白盒测试的目的是验证一个类的所有成员方法或函数(包括保护和私有成员)是否足够强壮

(robust),当遇到各种预期或非预期的输入时它们的执行是否正确。

C++Test 通过自动生成和执行大量的测试用例,检查代码在各种输入下的行为,并报告异常

行为。这是一个非常好的做进一步测试和调整测试用例的开始点,例如继续进行黑盒测试。

5黑盒测试

黑盒测试的目的是检查类的功能性是否正确,即类的接口的执行(输入和输出)是否符合说

明书(设计文档)。

你需要比较一个测试用例的实际执行结果(输出)是否与预期的输出一致。在C++Test 中,

第1 次执行测试用例(自动或用户自定义)后,会将其结果自动保存在输出条件中,你可以使用上述结果也可以自己设置正确的预期输出(通过测试用例编辑器,见下节)。

6定制测试用例

使用“测试用例编辑器”定制或建立自己的测试用例。

C++Test 测试用例可以控制7 种类型的变量条件(取决于被测函数用了多少):

. 参数(Arguments): 函数的入口参数。

. 参数出口条件(Arguments Post): 函数执行完成时入口参数的状态。

. 返回值(Return): 函数的返回值。

. 对象前置条件(Pre Conditions> This): 测试开始前对象的条件。

. 对象后置条件(Post Conditions> This): 测试执行后对象的条件。

. 前置条件(Pre Conditions> Externals): 测试开始前全局变量的条件。

. 后置条件(Post Conditions> Externals): 测试执行后全局变量的条件。

C++Test 能够支持任意类型的变量和条件,并且你可以控制到每个变量的任意层次上或最底

层的基本类型变量,你可以任意修改和扩充变量的值。

7对象库

如果你需要经常用到一个对象的一组变量值,可以将它保存到对象库中。在定制其它测试用

例时可以直接复制这组值。

关于测试用例的各种复杂应用见下面各个例子。

8回归测试

回归测试的目的是为了保证对代码的任何修改以后没有引入错误。因此一定要保持与前次测

试的可比性。在C++Test 中,你可以有多种方式执行已有的测试用例,如这个项目、一个文件、类、方法、若干测试用例或单个测试用例。

9自动测试尽可能多的分支和边界条件

C++Test 具有一定的“智能”,能够自动分析你的代码,根据一些特征值自动生成能够更好

地执行各个条件分支的测试用例,提高代码覆盖性。虽然目前这种能力还是比较初步,但在

市场上还是独有的,是ParaSoft 自动测试用例生成技术专利的一部分,能够有效地提高测试覆盖性。

C++Test 的这种能力主要表现在几个方面:

. 根据输入参数的类型特征生成测试用例。

. 你可以设置特定的边界值,用于自动生成测试用例。

. 自动分析代码中的边界条件,并自动生成相应的测试用例。

9.1【例】发现条件中的整型边界条件

#define SIZE 88

int user_input_handler(int i)

{

int result = 0;

if (i > SIZE) result = -1;

else if (i <33) result = 1;

return result;

}

C++Test 能够自动识别第一个条件中的SIZE(并使用SIZE 的实际值88)和第二个条件中的33,并自动生成相应的测试用例。

9.2【例】发现条件中的字符型边界条件

D:\\ParaSoft\\C++Test\\examples\\extern_func.cpp:

#include

int user_input_handler(char *user_input, char * output)

{

int result = 0;

if (strcmp("load", user_input) == 0) {        //比较 user_input 是否=“load” 

strcpy(output,user_input);                 ///,如果相等,拷贝到output

} else if (strcmp("save", user_input) == 0) {

strcpy(output, user_input);

} else if (strcmp("quit", user_input) == 0) {

strcpy(output, user_input);

} else {

result = -1;          //如果不等,返回值为-1

}

return result;           //拷贝后返回值为0

}

在自动生成的测试用例中使用了实际的判断条件“load”、“save”和“quit”,从而保证测

试用例可以执行各个分支。入口参数为user_input和output

9.3【例】使用枚举类型生成测试用例的输入值

enum Mode {TO, FROM};

int GetStatus(Mode mode) {

int status;

switch (mode) {

case TO:

status = 0;

break;

case FROM:

status = 1;

break;

default:

status = -1;

break;

}

return status;

}

自动生成的测试用例如下:

9.4【例】使用特殊字符

D:\\ParaSoft\\C++Test\\examples\\heuristic.cpp:

char *encode_char(char value) {

char *result = new char[5];

char *encoded = 0;

switch (value) {

case '&':

encoded = "AND";

break;

case '%':

encoded = "PRC";

break;

case '$':

encoded = "DLR";

break;

case '*':

encoded = "ASX";

break;

case '/':

encoded = "DVD";

break;

case '^':

encoded = "PWR";

break;

case '#':

encoded = "HSH";

break;

default :

break;

}

char *iter = result;

//should check to see if 'encoded' is null

while (*encoded) {

*iter++ = *encoded++;

}

*iter = 0;

return result;

}

识别case 子句条件与输入参数的关系,并在自动生成测试用例时可以使用特殊字符。

10处理复杂数据类型

C++Test 在自动生成和用户自定义测试用例和桩时,能够处理复杂的数据类型,如类、结构、

枚举、自定义类型和指针等,允许用户对每一个基本项的内容进行控制。

10.1【例】用类、枚举和自定义类型做输入/输出

D:\\ParaSoft\\C++Test\\examples\estsuite.cpp:

enum TestStatus {BeforeExecution, DuringExecution, Broken, Failed, Passed};

enum { TESTS_NR = 20 };

enum { PARAMETERS_NR = 8};

typedef float TestParameters[PARAMETERS_NR];

class TestSuite {

private:

TestStatus _status;

TestParameters _testParameters;

public:

TestSuite() : _status(BeforeExecution) {}

TestStatus getStatus() { return _status; }

int setParameter(int i, float f);

friend int test(TestSuite&);

};

int TestSuite::setParameter(int i, float f)

{

if (i < PARAMETERS_NR) {

_testParameters[i] = f;

return 0;

} else {

return -1;

}

}

void runTests()

{

TestSuite t[TESTS_NR];

for (int i=0; i < TESTS_NR; ++i) {

test(t[i]);

}

}

TestStatus executeTest(TestParameters);

int test(TestSuite& t) // 用类作参数,类中含有两个私有数据成员。

{

if (t._status != BeforeExecution) {

return -1;

}

t._status = DuringExecution;

t._status = executeTest(t._testParameters);

if (t._status != Passed && t._status != Failed) {

t._status = Broken;

return -1;

}

return 0;

}

对于成员函数TestStatus getStatus(),其返回类型是枚举型,如下图。

对于成员函数int test(TestSuite& t),其输入参数类型是复杂数据类型(类),且其中含有两

个复杂类型(枚举和自定义类型)。下图是一个自动生成的测试用例。注意到右边的编辑框,

复杂类型中的每一个底层项都是可以控制的,用户也可以自己设定(如果你要增加或定制测

试用例)。

10.2【例】用结构、枚举和指针类型做输入/输出

D:\\ParaSoft\\C++Test\\examples\ce.cpp:

enum Priority {LOW, NORMAL, HIGH, CRITICAL};

enum Mode {TO, FROM};

typedef int* PayData;

// structure for client data

struct Client {

int id;

char* name;

char* address;

PayData accounts;

};

// structure for delivery data

struct Delivery {

int senderId;

int recipientId;

char* name;

char category;

float weight;

Priority priority;

bool confirmDelivery;

};

// send specified delivery

void send_delivery(Delivery *dlvr);

// send all deliveries to / from specified client | 使用复杂结构

int send_all(Mode mode, Client clnt, Delivery *dlvrs, int count) {

int sent = 0;

int currentId = -1;

Delivery* currentDlvr = dlvrs;

for (int i = 0; i < count; i++, currentDlvr++) {

switch (mode) {

case TO:

currentId = currentDlvr->recipientId;

break;

case FROM:

currentId = currentDlvr->senderId;

default:

currentId = -1;

break;

}

if (currentId == clnt.id) {

send_delivery(currentDlvr);

sent++;

}

}

return sent;

}

我们注意到,结构Client 中包含枚举类型,结构Delivery 中包含自定义类型。函数send_all

的输入参数包括枚举(Mode)、结构本身(Client)和结构指针(Delivery *)。下图是一个

自动生成的测试用例:

注意:结构指针不仅是传递一个指针,复杂结构中的每一个基本项都是可以控制的。再注意

到Client 中的PayData 项和Delivery *项,右边有一个选项[ALLOC 1],因为它们都是指针型,

你还可以给这样的项增加多个元素,并按需要设置其值,如下图:

11处理复杂嵌套类型

C++Test 还能处理一些非常复杂的类型,如多层嵌套的类和结构等对象,并允许你在每一层

上对基本项进行控制。

11.1【例】应用多层嵌套类

D:\\ParaSoft\\C++Test\\examples\\nested.cpp:

class Main { // 多层嵌套类

public:

class NestedClass {

public:

class NestedInNestedClass {

public:

int getX()

{

return _x;

}

int getY() { return _y; }

private:

int _x;

int _y;

};

NestedInNestedClass getN() { return _n; }

int getX() { return _x; }

float getY() { return _y; }

private:

NestedInNestedClass _n;

int _x;

int _y;

};

enum NestedEnum {

X, Y

};

NestedClass getN() { return _n; }

NestedEnum getE() { return _e; }

NestedEnum setE(NestedEnum e) {

NestedEnum old = _e;

_e = e;

return old;

}

int getX() { return _x; }

int getY() { return _y; }

private:

NestedClass _n;

NestedEnum _e;

int _x;

int _y;

};

int sum(Main& m);

int sumXs(Main& m)

{

Main::NestedEnum old = m.setE(Main::X);

int s = sum(m);

m.setE(old);

return s;

}

int sumYs(Main& m)

{

Main::NestedEnum old = m.setE(Main::Y);

int s = sum(m);

m.setE(old);

return s;

}

int sum(Main& m)

{

if (m.getE() == Main::X) {

return m.getX() + m.getN().getX() + m.getN().getN().getX();

} else if (m.getE() == Main::Y) {

return m.getY() + m.getN().getY() + m.getN().getN().getY();

}

return -1;

}

C++Test 的测试用例可以对嵌套中的每一层进行控制,使得用户保持对测试用例的弹性。下

图是一个最内层嵌套类一个成员函数的自动测试用例。

12自定义桩时返回复杂数据类型

桩(stub)是单元测试中对外部调用的处理。C++Test 允许三种桩的方式:使用已有的(系统库、第三方或自己的)、C++Test 自动生成的和完全由用户自己定义的,对处理桩的问题提供了最大的弹性。对于桩的复杂返回类型,你也可以象输入/输出参数一样自如地控制。

让我们来考虑下面一段代码(对前面的代码作了一点改变,使得send_delivery 返回结构类型):

12.1【例】桩返回类型为结构指针

struct Delivery {

int senderId;

int recipientId;

char* name;

char category;

float weight;

bool confirmDelivery;

};

// send specified delivery

Delivery * send_delivery(Delivery *dlvr); // 返回结构指针

// send all deliveries to / from specified client

int send_all(Delivery *dlvrs) {

Delivery * currentDlvr;

currentDlvr = send_delivery(currentDlvr);

return 0;

}

其中,send_all 要调用send_delivery,返回一个结构指针。因为当前没有定义send_delivery,

所以C++Test 为其自动生成桩。如果需要的话,你也可以定义自己的桩或为自动桩增加特定的参数,如下图所示:

13初始化对象

C++Test 在执行自动测试用例时能够自动初始化下列类型的对象:

. 复杂类型的函数参数(入口参数)

. 成员函数的隐含This 指针(前置条件)

. 全局对象(后置条件)

当使用自定义测试用例时,你能够选择使用那个构造函数来初始化对象。

13.1【例】使用用户定义构造函数初始化对象

D:\\ParaSoft\\C++Test\\examples\\inheritance.cpp:

class Auto

{

protected:

char * _model;

unsigned int _carPrice;

unsigned int _mpg;

double _gasPrice;

public:

// default constructor

Auto(){}

// user-defined constructor

Auto(char * new_Name, int new_price, int new_mpg, double new_cost)

:_model(new_Name), _carPrice(new_price), _mpg(new_mpg), _gasPrice(new_cost)

{ }

virtual ~Auto(){}

// another way to initialize an automobile

virtual void init(char * name, int price, int mpg, double cost)

{

_model = name;

_carPrice = price;

_mpg = mpg;

_gasPrice = cost;

}

virtual char * getname()

{

return _model;

}

// the cost of the car is the sum of the price of the car plus the mileage

// divide by gas efficiency and times the price of a gallon of gas

virtual double totalCost(int mile)

{

// should make sure _mpg != 0;

return _carPrice + mile/_mpg * _gasPrice;

}

};

// Sports inherits from Auto, it uses its constructor

class Sports:public Auto

{

public:

Sports(char * new_name, int new_price, int new_mpg, double new_cost)

:Auto(new_name, new_price, new_mpg, new_cost)

{ }

Sports():Auto(){}

virtual ~Sports(){}

};

// mySports is a typical Sports car which has a constant name "myCar"

// when using the user-defined constructor, "myCar" is passed into 'new_name'

class mySports:public Sports

{

public:

mySports(int new_price, int new_mpg, double new_cost)

:Sports("myCar", new_price, new_mpg, new_cost)

{ }

mySports():Sports(){}

virtual ~mySports(){}

};

// 's' uses user-defined constructor to initialize object

double costOfaCar_1 (Sports & s, int miles)

{

return s.totalCost(miles);

}

// 's' uses default constructor, and use 'init' function to initialize object

double costOfaCar_2 (Sports & s, int miles)

{

s.init("Super", 20000, 26, 1.5);

return s.totalCost(miles);

}

// by using the user-defined constructor, 'getname()' will always return "myCar"

char * nameOfCar(mySports & m)

{

return m.getname();

}

例如,在测试costOfaCar_1 函数时,可以指定用那个构造函数初始化对象。

1)加入一个测试用例。

2)展开测试用例,右键点击Sports& s 节点,选择Use Constructors。

3)然后双击Sports()节点,选择用户定义的构造函数。

4)然后设置初始化参数。

14自动测试用户定义构造函数和重载函数

C++Test 可以对类的每一个函数或方法(包括用户自定义构造函数和重载函数)进行自动测

试,确保其正确性。

【例】测试用户定义构造函数和重载函数

D:\\ParaSoft\\C++Test\\examples\\complex.cpp:

class Complex {

public:

Complex(float re = 0, float im = 0) : _re(re), _im(im) {}

Complex operator+(const Complex&);

Complex operator-(const Complex&);

private:

float _re;

float _im;

};

Complex Complex::operator+(const Complex& c)

{

return Complex(this->_re + c._re, this->_im + c._im);

}

Complex Complex::operator-(const Complex& c)

{

return Complex(this->_re - c._re, this->_im - c._im);

}

Complex testComplexOperators(Complex& a, Complex& b)

{

Complex zero;

Complex neg_a = zero - a;

Complex neg_a_sum_b = neg_a - b;

return a + b + neg_a_sum_b;

//this function should always return complex zero value

}

15测试模板(template)应用

模板是C++语言中比较复杂的对象,C++Test 能够处理这种应用。

C++Test 不能直接测试模板函数或类本身,但可以测试模板函数和类的任何实例,并包括下

列特性:

. 测试任何用模板作为参数的非模板函数。

. 测试任何返回类型为模板对象的函数。

. 在函数内部使用预先实例化的对象。

15.1【例】自动测试模板应用

D:\\ParaSoft\\C++Test\\examples\empl.cpp:

template

class Bucket

{

public:

T _dataT;

// constructor

Bucket (T _newT):_dataT(_newT){}

T getT()

{

return _dataT;

}

T addT( T _newData)

{

return _dataT + _newData;

}

};

// creates a global Templa object smg with and the value 10

Bucket smg(10);

// func_1 takes in a Templa object instantiated when passing into function argument

int func_1(Bucket templ)

{

return templ._dataT;

}

// func_2 uses the global object smg and returns the object itself

Bucket func_2()

{

return smg;

}

// func_3 uses global object smg & returns the value of its public data member

int func_3()

{

return smg._dataT;

}

// func_4 uses global object smg & calls its public function getT()

Bucket func_4()

{

return smg.getT();

}

// func_5 uses global object smg & pass in another Templa object to test 'addT' function

Bucket func_5(Bucket templ)

{

return smg.addT(templ._dataT);

}

该例子中包含了使用模板的几种情形,其中func_5 比较复杂。C++Test 能够对模板对象进行自动测试,下图是func_5 的一个自动测试用例。

16自动捕获代码异常

C++Test 在测试过程中能够自动捕获代码中的异常状态,如内存存取违例、下标越界、被0

除等。这样的错误往往是造成程序莫名其妙的死机的根源。出现这种情况是因为缺少必要的

代码对数据流的合理性进行有效的检查和防范。原因有多种,如编程时考虑不周,“觉得”

通过的数据“应该是”合理的,我的程序“不会”产生不合理的数据等等。如果检测出这样

的代码异常,应该通过修改代码,排除异常错误。

【例】存取异常

char *l2a_convert_slave(char *string, unsigned long number)

{

// missing checking

16.1// if 'string' is not null / if it's capable enough

D:\\ParaSoft\\C++Test\\examples\\exception_handle.cpp:

// helper function for l2a_convert() - converts unsigned values only

if (number >= 10) {

string = l2a_convert_slave(string, number / 10);

}

*string++ = "01234567"[number % 10];

return string;

}

// working function for l2a()

char *l2a_convert(char *buffer, long number)

{

// missing checking

// if 'buffer' is not null / if it's capable enough

if (number < 0) {

*buffer++ = '-';

number = -number;

}

buffer = l2a_convert_slave(buffer, (unsigned long)number);

*buffer = '\\0';

return buffer;

}

...... 

C++Test 的自动测试发现两处代码有异常。例如:

l2a_convert 函数在测试参数buffer 为NULL 时,*buffer++操作发生异常。应该在前面增加判断buffer 是否为NULL 的代码,排除隐患。

17多文件测试

同时测试多个文件给了你更大的弹性,便于建立更实际的测试场景。

C++Test 通过建立测试单元(Create Test Unit)功能支持多文件测试:

1)选择菜单Project> Create Test Unit,弹出一个窗口,输入一个测试单元的名称。

点击左边项目树中的测试单元名,右边结果区中的Source Code tab 变成了Test Unit tab。你可

以从当前打开的文件列表中加入文件,也可以打开并加入新的文件。我们加入..\\Parasoft\\C++Test2.0\\examples\\MultiFileSupport 下的文件:

这时你就可以像测试一个文件一样对测试单元进行测试了。

18函数序列测试

有时你需要对一些函数进行组合测试,或测试其特定的调用序列。使用测试单元功能就可以

很容易地做到这点。执行下列步骤:

. 编写一个文件,包含你希望的函数调用序列(例如一个函数的返回值可以用于另一个函数

的输入)。注意要包含所有必要的#include 文件。

. 通过定义全局变量控制中间值。这些全局变量可以在测试函数中作为前置和后置条件访问。

. 建立一个测试单元项目,并加入写好的文件以及其它必要的文件(包含在测试函数中使用

的函数)。

. 像测试一个文件一样对测试单元进行测试。

下面是函数序列测试文件的一个例子:

#include "cstack.h"

int MyTest()

{

CharStack cs;

cs.push('a');

cs.push('b');

cs.pop();

cs.push('z');

cs.pop();

cs.pop();

return cs.size();

}

int MyTest2()

{

CharStack cs;

cs.push('a');

cs.push('b');

cs.pop();

cs.push('z');

cs.pop();

cs.pop();

cs.push('1');

cs.push('2');

return cs.size();

}

19观察测试覆盖性

C++Test 在动态测试时提供实时的覆盖性信息,包括每一行已经执行的次数和汇总的覆盖性

数据。

要监视覆盖性,首先选择:Settings> Enable Coverage,然后执行测试用例,就可以看到结果。

你还可以将测试结果保存到文件中:

Line coverage for file: D:\\ParaSoft\\C++Test2.0\\examples\\cpptest_demo.cpp

--------------------------------------------------------------

File [D:\\ParaSoft\\C++Test2.0\\examples\\cpptest_demo.cpp] 17/31 (54%)

Class [Data] 17/31 (54%)

Function [unsigned int getSize()] 3/3 (100%)

Function [char* getData()] 0/3 (0%)

Function [void copyToBuffer(char*)] 6/6 (100%)

Function [int bufLen()] 0/8 (0%)

Function [~Data()] 0/2 (0%)

Function [Data(char)] 8/9 (88%)

--------------------------------------------------------------

D:\\ParaSoft\\C++Test2.0\\examples\\cpptest_demo.cpp

--------------------------------------------------------------

Line | Count | Source

--------------------------------------------------------------

1 | | // This class holds simple character buffer of size 5.

......

11 | | class Data

12 | | {

13 | | public:

14 | | // constructor should be declared 'explicit'

15 | 6 | Data(char fill = '\\0') {

16 | 6 | const unsigned SZ = getSize();

17 | 6 | _data = new char [SZ];

18 | 6 | if (_data == 0) {

19 | | throw "Out of memory";

20 | | }

21 | 6 | for (unsigned i = 0; i < SZ; ++ i) {

22 | 30 | *(_data + i) = fill;

23 | | }

24 | 6 | _data[SZ - 1] = '\\0';

25 | 6 | }

......

文档

C++Test介绍及使用说明

1个人意见1.1一个例子对以下的函数(在其提供的例子程序divide_by_zero.cpp中)//calculatessumofspecifiedvaluesintget_sum(int*data,unsignedintsize){//missingcheckingif'data'existsintsum=0;for(inti=0;i
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

Top