单元测试方法范文

时间:2023-03-05 16:49:49

单元测试方法

单元测试方法范文第1篇

关键词:飞行控制软件;单元测试;动态测试

中图分类号:TP301

文献标识码:A 文章编号:1672-7800(2015)005-0029-03

作者简介:刘思思(1985-),女,陕西商洛人,硕士,上海机电工程研究所工程师,研究方向为飞行控制软件开发、系统集成与验证;刘迪(1985-),男,黑龙江哈尔滨人,硕士,上海机电工程研究所工程师,研究方向为制导控制系统设计与仿真。

0 引言

在飞行控制软件(简称飞控软件)开发过程中,单元测试环节必不可少。其中,静态度量指标可以用专门的工具很方便得出其具体数值,而动态测试虽然也有专门的工具,但编写测试用例需要花费大量时间和精力。当前,航天多型号开发任务重,迫切需要应用自动化的测试工具软件来提高动态测试的工作效率。

本文结合飞控软件的特点,论述通过自动生成测试用例的工具软件Cantata6.2进行单元动态测试的方法。

1 飞行控制软件特点

飞控软件的主要功能是完成相关设备之间的实时信息交互与控制解算,从而实现飞行过程中姿态和位置的控制。飞控软件主要分为应用层软件、接口协议层软件和底层驱动软件3个部分,软件架构如图1所示。

应用层软件由实现姿态和位置控制的各功能模块组成;接口协议层软件主要为飞行控制设备与其它设备之间通信的协议模块;底层驱动软件主要由飞行控制设备的接口驱动模块以及硬件输入输出模块组成。

飞控软件嵌入在飞控设备中,具有实时性高、时序和逻辑复杂、可靠性高的特点。首先,要确保底层驱动软件和接口协议软件的正确性,使得各类信号得以正确传输;其次,要确保软件与控制算法模型的一致性,输入输出及解算正确;最后,要确保软件时序和逻辑的正确性。只有这样才能保证飞行控制系统正常工作。

2 飞行控制软件单元测试的意义

对飞控软件的最小组成单位――函数进行测试的目的在于检验其能否正确地实现其功能,满足性能指标和接口要求。通过语句(SC)、条件(DC)、修正条件判断(MC/DC)等覆盖率指标评价程序结构,及早发现软件代码中的编码和逻辑错误。

对控软件来说,被测函数已经完成了编码和调试,能够通过编译和链接进行单元测试。此外,不考虑每个模块与其它模块之间的关系,为每个模块设计驱动模块和桩模块,每个模块进行独立的单元测试,各模块的单元测试可以并行进行,能够提高测试效率,也较容易实现100%的覆盖率指标要求[1]。

3 Cantata6.2测试工具

3.1 Cantata6.2简介

Cantata6.2采用先进的代码分析器和AutoTest技术,智能分析被测代码,扫描代码的所有可能路径,根据选定的覆盖率标准,自动生成满足100%覆盖率的测试用例。对全局变量、返回值自动赋期望值,并包含对全局变量、返回值、调用函数参数传递等进行检查。对形参为复杂类型,如结构体指针的情况,能自动生成相应的测试对象,即构造一个结构体数组,将结构体数组的地址赋给形参。自动生成桩函数,在测试工程中替代真实的外部函数。使用Cantata6.2进行单元测试的原理如图2所示。

用户可以使用Cantata6.2工具AutoTest选择相应的覆盖率规则集,通常航天A级软件要满足修正条件判断(MC/DC)覆盖率100%,B级软件要满足分支判断(DC)覆盖率指标100%,C级软件要满足语句(SC)覆盖率指标100%。飞控软件通常均为A级软件,选择DO-178B/ED-12B Level A Coverage规则,自动生成满足SC、DC、MC/DC3个覆盖率指标要求的测试脚本文件。

3.2 含有桩函数的测试实例

本文以飞控软件的指令形成函数模块为例,检验Cantata6.2的动态测试功能。该函数模块的主要功能是形成稳定控制系统姿态控制等的指令信号。代码框架如下:

void Instruction (C_INSTRCUTION *C_)

{

……; //定义局部变量

if(C_->fInTT < t1)

{

……; //控制解算

}

else

{

……; //控制解算

Function1(C_);

……;

if(C_-> fInTT < t2) //注①

{

……;

}

else

{

……;

}

……;

}

}

利用Cantata6.2进行动态测试。自动生成10个测试用例并执行完后,语句覆盖率和分支判断覆盖率都没有达到100%,源代码中注①处标注的条件判断的假分支没有得到执行。于是,手动添加一个测试用例,使得在给定的输入条件下结构体变量C_-> fInTT的值落在[t2,∞)的区间内,接着重新执行该测试用例,结果还是执行不到该假分支。仔细分析代码后发现,该分支中的条件判断表达式中的结构体变量C_-> fInTT的值已被桩函数Function1(C_)修改。

处理方法如下:第一步,在Cantata6.2的调用接口控制界面中,为该桩函数添加一个新的桩函数实例,并手动修改结构体变量C_-> fInTT的值,该数值应大于或等于t2;第二步,在Cantata6.2测试用例界面,将调用序列更改为新的桩函数实例。至此,执行全部11个测试用例之后,满足语句和分支判断覆盖率全达到100%的指标要求。

3.3 编译器对测试结果的影响

飞行控制软件的编译器目前主要使用CCS2.2或CCS3.3,在用Cantata6.2进行单元测试时,CCS被设置为Simulator模式,Cantata6.2会自动调用CCS,执行编译好的测试中间文件,进而生成测试结果文件。测试过程中,笔者发现对于如下代码段,Cantata6.2自动生成的测试用例对X自动赋值为0.9999,调用CCS2.2执行用例后,代码运行的实际路径与期望路径不一致,测试结果不能达到100%的分支覆盖率指标要求。

#define ZEROP 0.00001

void Function2 (void)

{

if(X

{

……;

}

else

{

……;

}

……;

}

笔者分别在CCS2.2和CCS3.3编译器环境下,验证了该代码段的运行情况,最终得出结论如下:①在CCS2.2编译器下,程序执行真分支,与期望不一致,结果不正确;②在CCS3.3编译器下,程序执行假分支,与期望一致,结果正确。上述结果表明,不同的编译器版本影响程序实际执行路径的正确性。

4 基控软件的Cantata6.2使用策略

4.1 Cantata6.2使用策略

飞控软件中包含很多复杂的结构体数据类型,Cantata6.2能够对结构体类型自动赋值,不用手动一一赋值;而且飞控软件涉及大量数学计算,Catata6.2的测试脚本是开放的纯C代码,可在其脚本管理器界面或测试脚本中直接修改某个测试用例的变量值,提高测试效率。Cantata6.2测试工具是通用的,而飞控软件具有其特殊性,就二者的融合使用,笔者总结出如下经验:

(1)飞控软件中一般都包含do while(1)的死循环结构,测试时需要将这类死循环放开,测试用例才能执行完毕。

(2)飞控软件中包含有很多类似“x=x”的赋值操作,本义是在某些特定条件下,x的值不变,测试时要将这类语句注释起来,否则Cantata6.2会报错。

(3)当被测函数包含子函数时,Cantata6.2会自动作打桩处理,但桩函数有可能会修改某些全局变量的值,进而导致某个分支始终无法覆盖。这时,可以在该桩函数的调用接口添加一个桩函数实例,并手动修改该变量的值,再将调用序列更改为新的桩函数实例,如3.2小节所述实例。

(4)飞控软件作为嵌入式软件,最终是固化在飞控设备中,构成飞控系统运行。因此,软件一般都包含对硬件端口地址的操作,如果是从端口输出数据,测试时需要将这些代码注释起来,如果是读取某个地址的值,则可以自己定义一个变量代替该数值,否则将导致不能自动生成测试用例。

(5)飞控软件中的控制算法一般都包含有积分计算,开发人员一般习惯定义静态的局部变量,遇到这种情况时,应该将这些变量移到函数外部定义,否则会导致不能自动生成测试用例。

4.2 测试驱动开发

Cantata6.2测试工具能够自动生成测试用例,即使不满足语句、分支判断、修正条件判断覆盖率100%要求,测试人员也能很快根据覆盖率结果图示手动添加新的测试用例,使得该用例执行后覆盖到上一次未覆盖到的分支。但是,就笔者的使用经验而言,Cantata6.2对被测代码的要求比较高,被测代码要符合标准C要求,其头文件不能相互嵌套重复引用,否则一个.c文件和其相关的.h文件加载进去就会出现错误提示和警告,而且必须将这些错误提示解决完并通过编译后,才能进行下一步生成测试用例的工作。此外,由控软件具有逻辑复杂、运算量大的特点,要借助Cantata6.2的自动生成测试用例的功能快速完成飞控软件测试,这也对飞控软件的代码质量和框架结构提出了比较高的要求。在飞控软件框架结构和代码质量比较高的情况下,可以加载整个.c文件,一次性生成整个.c的全部测试用例,而不用单个函数去建测试工程,从而加快测试速度。笔者总结使用经验如下:

(1)飞控软件的自动驾驶仪模块根据控制系统的模型编写,模型中包含滚动、偏航、俯仰三通道控制解算算法,该模块代码最好拆成3个函数模块,单个模块代码行数要在200行以内,便于测试,代码结构也更加清晰。

(2)由控软件的特殊功能需求,同一个函数中包含多个条件表达式“与”或者“或”,再进行逻辑(即if else)判断的用法非常多,譬如if(条件表达式1&&条件表达式2||条件表达式3),开发人员在编写代码时,最好将这些条件表达式的计算在if判断之前完成,以有利于测试用例能够正常覆盖到期望的分支。

(3)依据航天软件工程化标准要求,飞控软件的安全关键性等级一般为A级,单元测试必须满足语句(SC)、分支判断(DC)、修正条件判断(MC/DC)覆盖率均达到100%。MC/DC要求每个判定中的每个条件都曾至少一次独立影响判定结果。由控系统的特殊算法需求,模型中涉及分段函数计算比较多,选择MC/DC覆盖率标准后,某些代码会覆盖不到。代码结构如下,斜体加粗部分为未覆盖到的代码:

if((x1>x2)&&(x1< (x2+const1)))

{

……;

}

else if( (x1>(x2+ const2))&&(x1< (x2+const3))) //注2:0

{

……;

}

else

{

……;

}

分析上述代码,笔者认为由于选择了修正条件判断覆盖率标准MC/DC,Cantata6.2认为第一个判断条件“x1>x2”的假分支不应再包含“x1>(x2+const2)”的判断条件。类似情况,建议控制系统设计师修改模型文件,或者软件开发人员优化程序结构。

(4)通过3.3小节中的实例,建议开发人员应该选择升级版本的编译器作为开发工具。此外,笔者尝试了将ZEROP定义为局部变量0.00001,结果程序无论在CCS2.2还是CCS3.3编译器下,均执行不到期望的正确分支,这对编码质量提出了较高要求。

5 结语

利用Cantata6.2自动生成测试用例的功能能够快速完成单元动态测试,促进开发人员提高编码质量,提高飞控软件的可移植性和可维护性,满足当前航天多型号软件开发和单元测试的工作需求。同时,工具内置的很多规则集能够帮助测试人员快速定位软件编码错误和框架问题,进而帮助开发人员更好的优化程序结构,进一步提高航天软件研制水平。

参考文献:

[1] 张猛,毛亮.航天嵌入式软件的单元测试方法探讨[J].航天器工程,2006(7):32-35.

[2] 陶幸辉,宋志刚.嵌入式飞控软件测试方法研究及实践[J].软件导刊,2011(8):14-16.

[3] 马飒飒,赵守伟,肖小峰.基于覆盖与故障注入的飞控软件测试技术研究[J].计算机测量与控制,2005,13(3):291-293.

[4] 王泉,张学宏,周敏刚,等.无人机飞控软件测试方法研究[J].航空计算技术,2008(3):78-81.

单元测试方法范文第2篇

【关键词】单元测试;cantata;测试用例

Abstract:The design of unit-testing case is one of the most important part of the unit testing,and it is an important guarantee for improving the software quality to design reasonable unit-testing cases.The article puts forward a designed method of unit-testing cases of a complex function,by introducing the cantata++ which is a testing tool and its function in unit testing,also considering that the true condition of making use of unit testing.This software unit-testing method is widely used in some other tastings and also well reputably.

Key Words:unit testing;cantata++;test case

1.引言

随着软件系统越来越复杂,在产品开发各阶段进行完全的软件测试也越来越重要,大多数软件开发者都已意识到这一点。但考虑到测试费用问题,软件开发者往往面临着在提高产品质量与减少费用之间进行选择的问题。IPL提供的Cantata测试软件应这种需要,在合理的费用下提供给软件开发者的强有效的软件测试工具。Cantata可以同时支持C和C++语言的测试,能够满足开发者进行高效的单元和集成测试的需求,该产品不仅能提高产品质量,还能帮助提高生产率。

作为专业软件测试工具,Cantata++除包含一些标准的特征之外,还提供了一些新功能:

(1)支持语句、判定和布尔代码覆盖率度量;

(2)支持运用白盒测试技术,自动获取私有类数据;

(3)支持面向对象测试用例的重用;

(4)图形化和XML形式的结果报告。[1]

2.单元测试用例的设计

软件质量的好坏很大程度上取决于测试用例的设计质量。不论程序员的编程水平、软件设计水平有多高,软件工程化执行得多好,如果没有通过合适质量的测试用例进行测试,其最终软件质量都是难以保证的。因此,测试用例设计是软件测试的最核心和最重要的内容之一。[2]

单元测试主要使用白盒测试技术,测试用例的设计方法一般分两种类型,即测试人员自己编写测试脚本和借助测试工具生成测试脚本框架后维护测试数据。Cantata++测试工具可用于生成和维护测试脚本,编译并运行测试可执行程序,查看测试结果和覆盖率数据。

3.基于cantata的测试用例设计方法

在cantata工具中常见的单元测试用例的实现方法很简单,不再赘述。本文主要介绍复杂函数实现的单元测试用例的设计方法。如单元测试的被测单元函数使用的函数形参是结构体变量和全局变量是结构体数组且结构体的成员是指针时,在设计测试用例时如何给结构体变量赋值?

3.1 函数的形参为结构体类型

Cantata测试工具自动生成的测试用例中,函数形参的默认值都是“NOT_SET”,编译测试脚本时不能被识别,给函数的形参赋正确的参数值是得到正确的测试结果的前提。设计带有结构体类型的形参的测试用例时,我们分别做了如下实验:

(1)按照在C语言中结构体变量成员赋值的方式给测试用例中的结构体变量赋值;

(2)使用改造C语言结构体变量成员赋值的方式把“->”改为“・”给测试用例中的结构体变量赋值。

编译结果证明两种赋值方式均不能被正确识别。

3.2 全局变量为结构体类型的数组变量,且其成员为指针

Cantata在自动生成测试用例时使用其本身封装的INITIALISE()函数给全局变量赋初值为0x55,以满足一般的测试需要。为达到充分测试的目的,需要给全局变量赋相应的数值,当全局变量为结构体类型的数组变量,且其成员为指针时,我们进行了如下实验:

(1)使用C语言中数组初始化的方式给结构体数组赋值;

(2)一个数组元素一个数据元素的方式给结构体数组赋值;

(3)使用分配内存的方式给结构体数组赋值。

编译结果证明三种赋值方式均不能被编译器识别。

结构体形参赋值时是不是因为该形参在赋值之前没有被分配内存空间所以无法赋值?结构体数组赋值的情况会不会因为cantata测试工具对编码规则要求较严格,必须按照相应的编程规则才可以编译通过?带着这种疑问我们查阅了大量编程规则的资料,通过反复实践,最终找到了解决该两个问题的办法。

其一,假设函数形参是如下两个结构体变量:

struct DIST* StrCount;

struct FILTER* StrFilter;

在测试用例脚本中可以通过下面的方式给结构体变量赋值:

StrCount = malloc(sizeof(struct DIST));

StrFilter = malloc(sizeof(struct FILTER));

memset(DIST_COUNT,0,sizeof(struct DIST));

memset(DIST_FILTER,0,sizeof(struct FILTER));

StrCount->cnt = 100; /*结构体成员赋初值*/

free(StrCount) ;

free(StrFilter) ;/*释放内存*/

如此赋值后的测试脚本文件加入测试工程后编译通过,得到了覆盖率测试结果,函数形参是结构体类型变量的测试用例设计的问题得以解决。

其二,假定定义如下的结构体数组:

PORT_CB g_PortCbTable[10];

其中:PORT_CB 为如下的结构体类型:

typedef struct

{

char num[16]; /* 端口名称*/

CONNOBJ* pObj; /* 端口句柄指针*/

}PORT_CB;

在测试用例脚本中,修改指针成员变量的方式为:

g_PortCbTable[0].pObj = (CONNOBJ*)-1;

g_PortCbTable[1].pObj = (CONNOBJ*)1U;

g_PortCbTable[2].pObj = (CONNOBJ*)1U;

g_PortCbTable[3].pObj = (CONNOBJ*)1U;

g_PortCbTable[4].pObj = (CONNOBJ*)1U;

g_PortCbTable[5].pObj = (CONNOBJ*) -12;

g_PortCbTable[6].pObj = (CONNOBJ*)2U;

g_PortCbTable[7].pObj = (CONNOBJ*)2U;

g_PortCbTable[8].pObj = (CONNOBJ*)2U;

g_PortCbTable[9].pObj = (CONNOBJ*)2U;

其中有后缀U或无后缀指明所赋常量的类型,强制转换类型不可以忽略。如此赋值后的测试脚本文件加入测试工程后编译通过,得到了覆盖率测试结果,至此全局变量为结构体类型的数组变量,且其成员为指针时,测试用例的设计问题得以解决。

4.小结

本文介绍了测试工具cantata的功能特性及其在单元测试中的应用,在此基础上提出了一种复杂单元函数的测试用例设计方法,该方法在类似的软件测试项目中得到了应用,在实践中取得了良好效果。

参考文献

[1]Cantata++ Reference Manual v6.1 2011,3.

[2]周伟明著.软件测试实践[M].电子工业出版社,2008:46.

作者简介:

魏银英,女,工程师,现供职于陕西凌云电器集团有限公司,主要从事软件开发、软件测试、GJB5000A体系修编与推广工作。

单元测试方法范文第3篇

关键词关键词:软件工程;软件质量;单元测试;测试框架;面向对向程序

中图分类号:TP302 文献标识码:A 文章编号文章编号:16727800(2013)008004503

0 引言

随着现代软件工程的不断发展,人们对软件质量和生产力的要求越来越高。软件测试技术和框架复用技术作为提高软件质量和生产力的有效手段,近年来倍受人们的重视。

传统的“黑盒”、“白盒”测试技术主要应用于面向过程的程序设计中。随着面向对象技术的发展,这种技术已不能满足软件测试的需要。自动化单元测试框架应用于面向对象单元测试中,通过它来实现单元测试自动化。

单元测试是对软件进行正确性检验的测试工作,是软件设计的最小单位。单元测试的目的主要是发现每个程序模块内部可能存在的错误。程序员的基本职责是单元测试,单元测试能力是程序员基本能力的体现,程序员必须对自己所编写的代码认真负责,软件的质量与程序员的工作效率直接受程序员单元测试能力高低的影响。

单元测试是一项很重要而且必要的工作。在实际工作中,许多程序员并不愿意对自己编写的代码进行测试。软件开发的工作压力大,大多数程序员们因为没有时间测试自己的代码,使程序的代码质量得不到保证,有些代码还需重新编写,程序员根本没有时间对代码进行测试。自动化单元测试框架能够从根本上解决这个问题,它可以使测试工作变得简单,这样更有助于程序员进行代码开发工作。

1 自动化单元测试框架设计目标

自动化单元测试框架的设计应达到以下目标:首先,框架简单,可以使测试程序的编写更简化。框架使用常见的工具设计,测试工作操作简单;其次,测试框架应能够使除作者以外的其他程序员进行代码测试,并能解释其结果,即将不同程序员的测试结合起来,且不发生相互冲突。最后,测试用例可以复用,可以以现有的测试为起点形成新的测试。

本文将以这些目标为指导,讨论如何用以Kent Beck和Ralph Johnson提出的“模式产生体系结构”的方式来设计框架系统。自动化单元测试框架的设计思想是从0开始根据设计问题应用设计模式,一个接一个逐步设计,直至获得最终合适的系统架构。其中实现部分采用Java语言来实现,并会使用UML图来表示各种类及类间关系。

2 面向对象自动化单元测试分析

自动化测试定义为:管理与实施各种测试活动,包括开发测试脚本、执行测试脚本,这样使验证测试需求更加方便,通过这些脚本实现了自动测试,可以把它称为自动测量工具。使用这种自动测试工具对增量软件集成测试提供了巨大的方便,增加了巨大的价值。每一个新的构件可以重用先前开发的测试脚本,即使需求和软件有变更,作为一个重要的控制机制,自动测试也能够确保每一次重新构建的稳定性与准确性。

3 面向对象自动化单元测试框架

自动化测试框架实质是一种自动测试工具,单元测试的核心问题是实现测试自动化。一个完整的自动化测试过程通常包括5个测试活动,分别是测试标识、测试设计、测试实现、测试执行与评估。测试用例针对被测试系统的各项功能准确地开发与设计,而且每一个测试用例都要按顺序执行这5个测试开发活动,测试开发活动如图1所示。

图1 测试活动

测试标识与测试设计这两个测试活动主要为智力活动,分别标识测试条件和设计测试用例。测试执行与测试比较这两个活动属于比较机械的活动,它们的功能分别为:执行测试用例、将测试输出结果并与期望输出结果值相比较。前两个活动决定了测试用例的质量,后两个活动适合自动化。在单元测试中,测试执行和测试比较这两个活动要重复多次,测试标识与测试设计通常只执行一次。因此,在单元测试过程中,重复性的活动特别需要自动化执行。

4 自动化单元测试设计与实现

首先构建对象来表达基本概念:Test Case(测试用例),然后将对象发送到测试框架,再由测试框架执行,最后报告测试结果。

采用Command命令模式将一个请求封装成一个对象,Command模式可以为每一个操作生成一个与之对应的对象,同时能够给出一个对应的执行方法。这样可以对多个用户请求进行排队,也可以将多个请求记录到日志,并使用不同的请求对客户进行参数化。具体实现方法如下:

其中的run()方法为模式中的执行方法,可以通过继承来重用该类,为了便于在测试失败时能够识别出失败的测试,每一个Test Case在创建时都要给出与之对应的名称,这样即可判断出失败的测试。

图1展示了测试框架组成部分的快照,也展示了应用于TestCase中的标记。

图1 测试框架组成部分

5 单元测试用例执行流程

在实际测试过程中,构造参数或资源、测试、释放资源为测试的业务逻辑过程。例如,在测试数据库的插入、更新、删除、查询等操作时,首先要对数据库进行连接,然后测试,最后释放连接。这样,在一个Test Case中有多个测试,需要反复书写代码,这增加了测试人员的工作量,不符合设计目标。

建立测试支架即为所有的测试建立一个共同的结构,可以解决以上问题,初始化代码、测试代码和释放资源的代码均放在测试支架上,每次运行测试代码之前,首先都运行初始化代码,最后运行释放资源代码。这样,每一个测试都会和与之对应的支架一起运行,而且测试结果互不影响,每一个结果都不会影响其它的测试结果。这样便实现了代码的复用,大大提高了软件单元测试的工作效率。

以上通过模板方法实现,模板方法的Template Method静态结构如图3所示。

其中,setUp方法初始化测试信息,如数据库的连接,cleanUp方法的功能是测试结束后释放资源。runTest方法的功能是进行测试业务逻辑。TestCase的方法的功能为进行测试逻辑框架的设计,run为模板方法。在这里,setUp和cleanUp可以被用来重写,由框架来进行调用。

6 测试结果收集

创建对象TestResult来收集运行的测试结果,实现代码如下:

UTF使软件开发者们更愿意接受测试代码的工作。有种种好处:UIT使测试用例的实现简单、一致且模块化;测试实现与执行的特性支持迭代、增量开发;重新运行测试包的便利使高频率的回归测试成为可能;同时它还能保证单元测试的持久性。此外,单元测试框架UTF也是可扩展的,例如,利用Decorator模式,可以不断向UTF添加新的功能;TestResult类也是框架的一个扩展点。客户能够自定义它们的TestResult类,例如, HTMLTestResult可将结果上报为一个HTML文档等。

参考文献参考文献:

[1] (美)普雷斯曼.软件工程:实践者的研究方法[M].北京:机械工业出版社,2011.

[2] (美)麦格雷戈.面向对象的软件测试[M].北京:机械工业出版社,2002.

[3] 刘中兵Java研究室.Java Web核心框架[M].北京:电子工业出版社, 2009.

单元测试方法范文第4篇

关键词:NetBeans;Junit;单元测试

中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)16-21255-03

NetBeans Platform Software Development Unit Testing Technology Research

TANG Jun

(Hunan Urban Construction College, Xiangtan 411101,China)

Abstract: Software development and software testing like the two brothers, they are inseparable, collaboration, there is only one objective, that is, successful development of high-quality software. Development and testing of the relationship between such closely, it is difficult to complete the demarcation of the two strict set. Unit testing as part of the test, the general commitment by the staff to coding, the module level who has been coded, who tests. So the test is not just testing things, as a coding staff also need to understand the basic test methods, through unit testing procedures to high-quality modules.

Key words: NetBeans; Junit; unit testing

1 引言

任何一个程序员都知道单元测试的重要性,没有经过严格测试的模块是“靠不住”的,组装过程会出现越来越多的Bug,甚至到了客户那里都不能正常工作,这简直就是一场灾难。虽然每个程序员都深刻的知道这点,但是很多时候在进度的压力下,程序员不得不放弃部分甚至是全部的单元测试。特别是在我国现在的国情下,献礼项目太多,建设方的领导为了在某个“有意义”的日子里使项目上线,往往迫使软件开发方违背客观事实,在不可能的工期内完工。程序员作为项目的最底层人员,自然没有力量来进行反抗,当他们加班加点都无法在规定时间完成,于是放弃测试就成为了他们的唯一选择。

很快这就成为一个恶性循环:压力越大,编写的测试越少。编写的测试越少,的效率越低,并且代码越不稳定。而效率越低并且越不精确,开发人员就感觉越有压力。

程序员的精力就在这样的恶性循环中被耗费掉。想要打破它需要一种外界的影响。所谓的这种外界的影响,其实就是一个简单的测试框架,它可以让我们通过做很少的测试,来达到完整的测试,减少我们编写测试代码的时间。

2 NetBeans 5.0对单元测试的支持

NetBeans IDE 5.0 引入了对基于 NetBeans 平台的 IDE 模块和富客户端程序开发的全面支持,直观的全新 GUI Builder Matisse,经过重新设计的对 CVS 的新支持,对 Sun Application Server 8.2、Weblogic9 和 JBoss 4 的支持,以及很多的编辑器增强功能。同时集成了Java开发工具中应用最广泛的单元测试工具Junit,使得在NetBeans下进行单元测试变得简单容易,提高了程序员进行单元测试的积极性。

可以使用NetBeans IDE创建以下类型的测试:

(1)空测试:没有测试方法的测试框架,尚未指定要测试的任何类。

(2)现有类的测试:包含实际测试方法的类,这些方法镜像了要测试的源的结构。

(3)测试套件:汇集在一起的几组测试类,允许对整个应用程序或项目进行测试。

可以使用以下方法生成并找到测试:在“项目”窗口中选择任何类或包节点,然后从“工具”> "JUnit" 菜单中进行选择。NetBeans 将单元测试表示为子树,这些子树反映了项目的 Java 包结构。每个测试类都由它所测试的类的名称后Test 单词组成(如 MyClassTest.java)。

每个项目都有一个缺省的测试包,所有的测试文件都在测试包内被组织。程序文件与测试文件被分割成两个独立的部分,在项目下分为一个SRC文件夹和一个TEST文件夹,互相不产生影响,测试完成后,只需要将SRC文件夹单独移开,并不需要TEST文件夹的支持。包结构如图1:

3 被测试模块的编写

新建一个Java类库的项目,项目名称为:MoneyChange,新建包moneychange,在包中添加类Money.class。

package moneychange;

public class Money {

private int fAmount;

private String fCurrency;

public Money(int amount,String currency) {

fAmount=amount;

fCurrency=currency;

}

………

}

该类有两个私有属性fAmount和fCurrency,构造函数在对类进行初始化的时候,对两个私有属性进行了赋值。Add方法对两个Money对象的现金(fAmount)进行相加,equals方法对两个Money对象的现金及货币单位进行比较是否相等。

4 创建单元测试

在项目窗口中的类Money.class上鼠标右键单击,在弹出的菜单中选择“工具”,并在子菜单中选择“创建Junit测试”。

这并不是创建单元测试的唯一方法,也可以通过“工具”下拉菜单中的“创建Junit测试”进行。接着弹出“创建测试”对话框,对测试类的类名以及需要生成的内容进行选择后,点击“确定”即可完成测试类的生成。

5 测试代码的修改

Junit不是万能的,不要指望它什么都帮你做好,在单元测试中,Junits 负责测试框架的生成,其他的事情还是需要程序员来做,如测试用例的设计和测试管理等。Junit针对上面代码生成的测试代码如下(已经删除部分注释):

package moneychange;

import junit.framework.*;

public class MoneyTest extends TestCase {

public MoneyTest(String testName) {

super(testName);}

protected void setUp() throws Exception {}

protected void tearDown() throws Exception {}

public void testAmount() {

System.out.println("amount");

Money instance = null;

int expResult = 0;

int result = instance.amount();

assertEquals(expResult, result);

fail("测试案例为原型。");}

public void testCurrency() {

System.out.println("currency");

Money instance = null;

String expResult = "";

String result = instance.currency();

assertEquals(expResult, result);

fail("测试案例为原型。");}

public void testAdd() {

System.out.println("add");

Money m = null;

Money instance = null;

Money expResult = null;

Money result = instance.add(m);

assertEquals(expResult, result);

fail("测试案例为原型。"); }

public void testEquals() {

System.out.println("equals");

Object anObject = null;

Money instance = null;

boolean expResult = true;

boolean result = instance.equals(anObject);

assertEquals(expResult, result);

fail("测试案例为原型。");}

}

此时,如果要执行测试,可以展开项目中的测试包,在测试类上鼠标右键单机,在弹出的菜单上选择“运行文件”,如图2所示。默认的测试类的执行结果是全部都不能通过的,结果如图3。

图2 图3

我们需要对生成的测试代码进行修改,将我们的测试用例以及期望的结果写入测试代码中,将fail(“测试案例为原型”);语句删除。testAdd的代码修改后如下:

public void testAdd() {

System.out.println("testAdd");

Money m12CHF= new Money(12, "CHF");

Money m14CHF= new Money(14, "CHF");

Money expected= new Money(26, "CHF");

Money result= m12CHF.add(m14CHF);

Assert.assertTrue(expected.equals(result));

}

该方法创建了两个进行加法操作的对象m12CHF和m14CHF,相加的结果为result对象,然后将result与期望的对象expected对象进行相等性测试。对修改后的测试代码再次执行结果如图4。

图4

对所有的测试用例进行测试通过后,即可以开始填写单元测试报告。通过单元测试的类比没有经过测试的类的稳定性将大大提高。

6 结束语

NetBeans集成的Junit单元测试工具为单元测试提供了一个很好的框架,我们无需将精力浪费在写单元测试代码上,而将更多的关注测试用例的设计。开发人员进行测试越来越方便,这也增强了开发人员进行单元测试的信心,在赶工期的同时将单元测试做好,是保证项目最后能够成功的一个重要手段。

参考文献:

[1] 蔡高亮.软件单元测试[J].信息技术与标准化,2008(Z1).

[2] 刘升华.单元测试自动化工具的研究与实现[J].计算机工程与设计, 2007(23).

[3] 郭雯.基于VC6.0的单元测试研究与实践[J].甘肃科技,2007(02).

[4] 隋智泉.一种改进的单元测试JUnit框架[J].电脑知识与技术,2007(08).

[5] 李海涛,欧全.浅析单元测试在项目开发中的应用.科技信息,2007(20).

单元测试方法范文第5篇

关键词:软件测试;单元测试;模拟对象

中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)05-00ppp-0c

1 引言

随着极限编程在实际软件开发项目中的推广,越来越多的项目开始采用测试驱动开发作为主要的软件开发方法。单元测试不仅优化了软件系统设计,还大大简化了功能测试的工作量[1]。但是另一方面.更多的项目在开始不久就发现在很多情况下针对一个类编写单元测试比较困难.随着项目的进行,越来越多的代码无法进行单元测试.到最后整个项目无法继续采用测试驱动的方式进行开发。因此,要将测试驱动开发真正在整个项目里贯彻执行,必须有一种方法能够相对容易的解决这些问题。本文将首先讨论了单元测试和无法或很难进行单元测试的情况,然后引入Mock Object的概念,基于Mock Object实现单元测试。接下来讨论在软件开发过程中引入Mock Object对测试和设计的影响。最后简述了Mock Object的局限性。

2 单元测试

2.1 什么是单元测试

单元测试是对程序中的单个子程序或过程进行测试的过程,也就是说,一开始并不是对整个程序进行测试,而是将注意力集中在对构成程序的较小模块的测试上面[2]。单元测试从两个角度进行测试:一是测试数据都是针对程序的功能来设计的黑盒测试;二是针对程序的逻辑结构来设计测试用例的白盒测试。

2.2 单元测试面对的难题

造成针对一个类难以进行单元测试的主要原因是因为这个类依赖于一些其它的难以测试的资源。主要有这三类最主要的资源:数据库,第三方组件和网络硬件资源。下面我们将对这三大类难以测试的资源进行分类讨论。

2.2.1 数据库

现在大部分的软件项目都会采用数据库作为数据存储。常见的开发团队会在每个开发人员的机器上安装一个本地的数据库,每个人针对自己的数据库进行开发调试。这样做的问题是:必须有一种方式同步数据库的设计。如果有一个人修改了数据库schema或者某个存储过程,这个修改必须同步到所有开发者的本地数据库以及测试服务器上。采用敏捷软件开发的很多项目组往往会浪费大量的时间在数据库设计同步上。更严重的是每周都会遇到由于数据库设计不同步,修改冲突导致的问题导致整个项目的中心源码库在Auto Build时失败。每个开发人员都有自己的测试数据,除了上面提到的需要把这些测试数据同步到所有开发机器和测试服务器上外,还面临更重大的问题。因为测试用例需要修改数据库,因此还必须准备一种机制能够在每一个测试用例执行结束后重新将所有的测试数据调入数据库。采用最简单直接的方法就是在每个测试用例执行前都将数据库清空,然后再将测试数据调入,这样会大大减慢单元测试的时间。单元测试时间越长,开发者就越不愿意执行这些测试用例,单元测试所发挥的作用越小,这也是很多测试驱动项目最终无法进行到底的一个重要原因。另一个非常严重的问题是为了清理测试环境,在针对商业逻辑的测试用例中加入了大量的数据访问层的代码。采用这样的方式强迫开发者在开发商业逻辑层的同时开发数据访问层,并且严重降低了可读性。

2.2.2 第三方组件或应用服务器

数据库是最常见的第三方服务器。除此以外在越来越多的项目中使用第三方的组件和应用服务器。例如:客户环境中的ERP系统,全球定位系统(GPS)的Web Service接口,绘图引擎等。对于这些第三方提供的内容,造成难以编写单元测试的最根本的原因有:一是系统不透明:对于大部分商业组件或者服务来说,一个很重要的内容是良好的封装。但这个特性带来的问题是在外界无法对其内部状态进行控制和访问。往往经过好几个操作后才能在外部观察到相应的变化。二是环境配置困难。由于项目组成员计算机配置不同,加入项目的时间不同,在项目中负责的内容不同导致无法为所有开发人员配置一个完全一致的环境。例如一个绘图引擎的开发版的license是按照一个局域网内部同时使用的人员个数收费的,就不可能只为了能够进行完整的单元测试就为只编写商业逻辑层的开发人员也安装一套。

2.2.3 网络资源和硬件资源

在稍大一些的项目中都或多或少的用到一些网络资源。例如将文件部署到远程的webDAV服务器上同时很多项目还会用到一些硬件资源。常见的有打印机、指纹识别验证或者条形码阅读器等。这些资源有两大特点导致很难针对与他们相关的类编写测试用例。

一是资源访问冲突。很多网络资源对于并发访问的响应协调是通过锁机制进行的,在实际项目中常见的是一个开发人员在调试本地代码时导致远端资源被锁定导致其它开发者无法访问这些资源。

二是环境可控因素。对于网络资源和硬件资源相关代码的测试与针对商业逻辑层代码的测试最大的不同是环境的不确定性。访问网络资源有可能遇到的异常情况非常多,例如网络忙造成访问超时,也有可能建立链接后数据传输失败,还有可能数据传输完成后校验失败。针对访问这些资源的代码进行的测试必须能够覆盖到所有可能出现的每一种情况。如果没有一个可控,并且是全自动的环境辅助单元测试的话,这项任务基本上不可能完成。

3 模拟对象

3.1 什么是模拟对象

Mock这个单词翻译成中文大概的意思是假的,模拟的。如图1所示:通过一个常见的对商业逻辑的测试描述了一个Mock Object。在图中我们可以看出:测试代码需要测试商业逻辑,而商业逻辑代码需要通过IMyDataAccess接口访问底层数据库,这就是数据库依赖问题。为了解决这个问题我们引入一个Mock Object,并将这个Mock Object而非真正的Data Access传递给商业逻辑代码进行测试。这里的Mock Object不需要实现任何逻辑只需要根据商业逻辑的需要返回适当的内容就可以了。

图1 使用Mock Object对商业逻辑进行测试

3.2 模拟对象实现单元测试应用实例

现在我们写好了类AccountService,具体如下:

public class AccountService {

private AccountManager accountManager;

public void setAccountManager(AccountManager manager) {

this.accountManager = manager;

}

public void transfer(String senderId, String beneficiaryId, long amount) {

Account sender = this.accountManager.findAccountForUser(senderId);

Account beneficiary =

this.accountManager.findAccountForUser(beneficiaryId);

sender.debit(amount);

beneficiary.credit(amount);

this.accountManager.updateAccount(sender);

this.accountManager.updateAccount(beneficiary);

}}

现在我们想测试transfer方法,它内部调用的AccountManager的两个方法。但是对于AccountManager来说,它只是个接口,如下:

public interface AccountManager {

Account findAccountForUser(String userId);

void updateAccount(Account account);

}

所以现在我们必须写个MockAccountManager对象。而且里面的方法体都是非常简单的,就是假定它就返回某某值。

我们这里还有Account类。

public class Account {

private String accountId;

private long balance;

public Account(String accountId, long initialBalance) {

this.accountId = accountId;

this.balance = initialBalance;

}public void debit(long amount) {

this.balance -= amount;

}

public void credit(long amount) {

this.balance += amount;

}

public long getBalance() {

return this.balance;

}

public String getAccountId() {

return accountId;

}}

public class AccountService1Tests extends TestCase {

public void testTransfer(){

AccountService as = new AccountService();

MockAccountManager mockAccountManager=new MockAccountManager();

Account accountA = new Account("A",3000);

Account accountB = new Account("B",2000);

mockAccountManager.addAccount(accountA);

mockAccountManager.addAccount(accountB);

as.setAccountManager(mockAccountManager);

as.transfer("A","B",1005);

assertEquals(accountA.getBalance(),1995);

assertEquals(accountB.getBalance(),3005);

}}

这里我们在假定AccountManager方法都工作正常的情况下,完成了对transfer方法的测试。

从以上代码可以看出,采用Mock Object进行的单元测试基本上可以分为下面几步:

(1)基于一个接口定义Mock并实现这个接口的所有函数。

(2)创建Mock Object的一个对象

(3)设置对象内部属性

(4)告诉对象测试代码希望看到的反应

(5)进行测试

(6)检查Mock Object的确按照希望的顺序进行工作。

3.3 模拟对象的优点

3.3.1 模拟对象作为测试手段的优点

Mock Object最直接的优点在于提供单元测试的质量和覆盖率:

(1)只要在测试中对期待发生的问题指定好执行的顺序引入Mock Object对象后的单元测试就是在一个完全可控的环境里进行的。也就是说我们再也不会无法定位一个“时隐时现”的bug。相反我们可以非常迅速的将问题定位在一个类的内部,而不是一个函数调用序列。

(2)于测试人员来说,最常见的问题是测试人员提交的bug无法在开发人员那里复现。有了Mock Object这个工具测试人员可以利用Mock Object明确的指定输入和输出编写一个测试用例让开发人员修复。

(3)超过8O% 的异常处理代码没有被充分测试过。主要原因是在没有Mock Object之前很多情况是无法由人工进行控制的,例如写文件失败网络连接超时,数据库数据传输失败或者从网络接收到的数据已经损坏。通过控制Mock Object我们很容易就可以模拟上面的这些情况。

3.3.2 模拟对象作为设计手段的优点

虽然Mock Object最直接的优点在于给予测试代码更多的可控性和可操作性,它最大的优点在于对软件设计的影响[3]。

(1)测试驱动开发与Mock Object一起使用,可以写出低耦合高内聚,非常优雅干净的代码。

(2)强迫设计者放弃对第三方库的强依赖关系,取而代之的是比较弱的依赖关系。

(3)设计人员可以将更大的注意力放在商业逻辑的实现和测试.由于Mock Object的存在,我们不需要实现数据访问层就可以对商业逻辑进行测试。而商业逻辑才是任何系统中对于客户最重要的内容,它的正确与否决定了整个系统是否能完成任务,它的稳定性决定了整个系统架构的稳定性。

(4)在项目初期,甚至是中期,将设计人员解放出来,不用对系统底层的基础设施做出判断。例如,在商业逻辑并不明确,需求还不稳定的时候,我们是更多根据感觉来做出很多重要的判断的,而这些判断往往导致比较关键的决定。例如,在项目之初,谁能够明确的回答到底需要什么样的数据库?Oracle?SQL Server?还是XML文件?到底需要什么样的队列服务器 MSMQ还是IBM―MQ?由于Mock Object的引入,我们可以将这些决策推迟到商业逻辑层更加明确之后进行,从而可以获得更加准确有针对性的答案。

3.4 模拟对象的局限性

Mock Object在实际项目中的应用存在一些限制,一些是由于Mock Object本身性质决定的,有一些则是由于其它类库设计存在的缺陷导致的。

(1)一个典型的不是Mock Object的问题,而是类库设计的问题。是Mock Object无法模拟比较深的对象树。有一些第三方的类库,尤其是一些消息处理函数的参数,提供的不是接口而是一些对象。往往这些对象内部有很多子对象,也就是我们常说的一棵大的对象树。我们需要花费太多的精力去构造这些对象来进行模拟,时间消耗巨大。

(2)一般性而言,单元测试的粒度越细,功能测试的粒度就可以越粗[4]。但是引入Mock Object的单元测试仍然无法取代功能测试。一个很好的例子就是误差积累的测试,哪怕每个单元的误差都在可接收范围内,我们仍然需要一个功能测试确保整体误差也是可以接受的。

4 结束语

模拟对象解决了传统单元测试的两个问题:一是如何将需要测试的代码与相关环境隔离;二是如何创建一个快速、可控的环境辅助测试开发。随着模拟对象技术的成熟,基于模拟对象的单元测试会越来越广泛地被采用。

参考文献:

[1]Kent Beck.测试驱动开发[M].北京:中国电力出版社,2003.

[2]Myers.王峰,陈杰译.软件测试的艺术(第二版)[M]. 北京:机械工业出版社,2006.50-52.

[3]David Astels.崔凯,译.测试驱动开发实用指南[M].北京:中国电力出版社,2004.120-130.

[4]Paul C Jorgensen.韩柯,杜旭涛,译.软件测试(第二版)[M].北京:机械工业出版社,2003.

收稿日期:2007-12-15

单元测试方法范文第6篇

【P键词】基于AOP角度 对象程序 单元测试 分析和阐述

单元测试是软件检测的主要任务之一,主要分为两种不同形式:

(1)建立在标准的基础上,利用黑盒来进行单元测试,来进行测试。

(2)建立在程序主体产生基础上,利用白盒检测系统和程序的逻辑性和合理性。

1 面向程序的单元测试弊端阐述

对于单元测试来说,其自身弊端不能忽视。包括文件性质自身弊端OPEN语句错误CLOSE语句错误,在缓存时,其缓存内存量和记录长度不符合,正文编写错误等等问题,会对整个系统的板块和数据带来影响。其次,测试错误处理现象的发生,也会影响描述正确性无法对错误定位,对板块和系统产生干预。

2 AOP编程阐述

2.1 1AOP编程重要性

AOP编程思想是社会发展的产物,是科学技术和社会经济发展的产物,具有时代性。对AOP编程思想发展背景进行分析和研究,发现AOP编程思想产生于1997年西方国家召开的编程论坛会议上,西方国家的研究人员,在编程会议中给出AOP编程这一理论思想。

单元检测,也被叫做板块检测,其主要服务对象为软件系统中的最小板块,针对系统中最小板块,来判断程序中板块的正确性。软件开发和设计的不断发展,增加了软件的种类和复杂性,增加软件测试的难度,增加单元测试的复杂性。面对这一发展形势,为了保证软件开发有效运作,保证软件的实际应用性,我国开始对软件测试和开发方法进行深入研究和分析,在长久的研究工作中,发现AOP编程思想具有实际应用,可以满足软件开发要求,满足单元测试发展目标。站在世界角度来说,增加AOP编程思想关注,对整个世界经济发展具有重要意义。

3 AOP编程思想在面向对象程序的单元测试应用

AOP编程思想在面向对象程序的单元测试应用,包括在对象程序单元测试应用,在契约的单元测试,独立单元检测应用。

3.1 AOP编程思想在面向对象程序单元测试步骤

对于AOP编程思想在面向对象程序应用来说,主要是对程序系统进行简化,简化为银行板块的模式,来对单元进行测试。AOP编程思想在面向对象程序应用主要包括以下几点内容。

(1)对系统的代码进行测试,对存在的与消费有关的信息和数据进行反馈,保证不同数据和信息积分反馈的真实性和准确性。详细来说,系统代码检测主要包含三个不同性质的对象,存钱、消费和取钱主体等等。系统代码可以对着三个不同主体的信息记录和代码件反馈。

(2)可以利用账户的优势,利用ID对使用账户和新增加的账户展开管库,保证了主体管理的可持续性,保证管理周期最大化。

(3)transfer具有自身的优势,这一方法可以展现不同账户的信息,增加了和账户的联系性,保证服务的完善性。

3.2 契约的单元测试

在对AOP编程思想在面向对象程序单元测试分析后,发现在利用传统的银行代码中,具有自身的便利性,但是也会存在众多问题。例如:BankAccount这一系统中,运作形式类别简单和便捷,但是其却会在应用过程中,出现数据和参数为零的现象,导致不同使用账户的财务为负数形式。面对这一发展现象,可以增加契约检测力度,来避免这一弊端的产生。契约单元测试主要包括以下两种形式。

(1)利用JAVA系统来运作。1.4系列是JAVA具有代表性的系列,其具有断言能力,满足契约检测的要求。

(2)对契约形式再次构建,保证设计的合理性和构建的科学性。这一构建工作,主要是针对技术来说,对服务主体对象应用技术展开设计,可以保证单元测试的完整性,保证软件的实际应用性,提高软件质量。

3.3 独立单元检测

独立单元的检测和测试具有自身的优势,降低了单元测试难度。例如:对于独立单员中存在遗留的代码来说,运作和替代具有自身难度,利用传统的检测方法,无法保证测试的真实性。在面对这一现象,可以利用AOP编程思想优势,对独立单元进行隔离处理,把单元换分为几个系统和板块,在一一处理,在保证单元独立性基础上,增加了对不同板块信息了解。其次,也可以利用Mocks这一方法展开测试,增加测试主体的协作性,对独立单元进行划分,给予隔离层。辩证来说,Mocks这一方法不具有逻辑性,无法满足逻辑需求。总的来看,AOP编程思想在独立单元检测中具有自身的应用优势,可以对系统中代码进行修改,和模仿主体的性能类似,利用ID来查找账户的信息,并把测试结果展现在系统中。

4 结束语

AOP编程思想是社会发展的产物,具有自身特点,可以利用账户的优势,利用ID对使用账户和新增加的账户展开管库,保证主体管理的可持续性,保证了管理周期最大化。

参考文献

[1]楼程伟,陈丽红.关于计算机编程思想与AOP编程思想的研究[J].电脑知识与技术,2015(24):52-53.

[2]谢林.AOP思想在项目中的应用与研究[J].电脑知识与技术,2010(15):4130-4132.

[3]杜玲玲.AOP技术在国库集中支付系统的应用[J].计算机应用与软件,2009(03):190-191+204.

[4]赵艳,刘同明.面向方面软件开发在J2EE企业应用系统中的实现[J].计算机技术与发展,2008(10):225-229.

[5]张永.AOP技术在自助设备运行管理系统中的应用[J].中国金融电脑,2008(08):91.

作者简介

张峻豪(1994-),吉林省长春市人。大学本科学历。职称:助理工程师。主要研究方向为软件测试。

作者单位

单元测试方法范文第7篇

关键词:单元测试;嵌入式软件;RTRT

信息技术的飞速发展带动在嵌入式系统中软件越来越多地取代硬件的功能,研究嵌入式软件测试技术用以保证软件质量成为近年来关注的热点。单元测试作为软件测试过程中的第一阶段,是软件测试的基础,效果会直接影响后期测试;另外,从修复软件缺陷与花费的成本关系考虑,在单元测试阶段修复缺陷将比在后一个阶段发现缺陷节约5~10倍的成本,可见无论从质量还是成本的角度单元测试都是非常关键的。但在实际测试中,仅依靠人工编写函数并统计分析结果的测试方法已不能满足测试准确性和测试效率的要求,要引进自动化的测试工具。RTRT是一个跨平台组件和运行时分析测试工具,支持测试的各个阶段,其单元测试自动生成测试用例模板,自动生成测试桩程序,自动运行测试程序,自动生成测试报告。

一、单元测试基本理论

(一)单元测试定义

单元测试是对每个最小的软件模块进行的正确性检验的测试,在于发现各模块内部可能存在的各种差错。包含模块接口测试、局部数据结构测试、路径测试、错误处理测试和边界测试,依据详细设计说明书和源程序清单,从程序的内部结构出发设计测试用例。主要采用白盒测试的测试用例,辅之以黑盒测试,使之对任何合理和不合理的输入,都能鉴别和响应。

(二)单元测试环境

单元是软件的基本组成模块,但本身不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,必须为每个单元测试开发驱动模块和桩模块。驱动模块相当于被测模块的主程序,它接收测试数据,把这些数据传送给被测模块,然后输出实测结果。桩模块是指用来替代被测模块调用的子模块。所以被测模块、与它相关的驱动模块及桩模块,同时包括测试用例是共同构成一个单元测试测试环境必需的要素。基于交叉开发环境,嵌入式软件单元测试环境分为基于宿主机和目标机环境两种。宿主机中单元测试与通用软件测试相同。目标机中的单元测试被测模块运行在目标机中,所有驱动模块和被测模块的数据传递都需要网线或者串口线完成,测试工具还要将测试结果再传送到宿主机中。单元测试都可以在宿主机平成,对特别指定在目标机中进行的测试必须在目标机完成。

(三)单元测试的覆盖评测

单元测试中主要的评价方法是覆盖评测,指所测试的源代码占代码总数的百分比。为了保证软件代码都被执行到,防止从不执行到的代码存在潜在的缺陷,导致产品失效。主要包括语句覆盖、判定覆盖、条件覆盖、判定-条件覆盖等。语句覆盖指设计较少的测试用例,使被测程序中每个语句至少执行一次;判定覆盖,即程序中每个判定的每个可能的结果都应该至少执行一次;条件覆盖,要求程序中每个判定的条件的所有可能值至少执行一次。由上述内容可知,一个完整的单元测试若完全利用人工来执行,则需要开发相应的测试驱动和桩程序,根据需求设计不同测试用例或大量测试用例组合,在宿主机和目标机环境下运行测试程序,判断测试用例是否正确,是否达到需要的测试覆盖率,最后编写测试报告。在代码修改的情况下,还要进行回归测试。测试过程比较繁琐且不受控,这导致很多程序员迫于时间和成本压力,逃避单元测试,结果本应单元测试解决的软件缺陷在后续的测试中较难查找和定位,花费更多的时间和成本来修复问题。自动化测试工具解决了由传统手工测试带来的困扰,典型的嵌入式软件测试工具包括CodeTest、Testbed和RTRT,即Rational Test RealTime的首字母缩写,具有强大的测试分析功能。

二、IBM RTRT嵌入式软件单元测试

(一)RTRT简介

RTRT是IBM Ratioanl提供的嵌入式软件代码级自动化测试工具集,成功地提供了自动化的、可重复的、可追踪判定的、标准化的测试,对提高嵌入式软件可靠性和开发测试速度起着巨大的帮助作用。所具有的突出特性如下:

1.支持广泛的测试功能,覆盖测试的各个阶段,包括静态度量、代码规则检查、单元测试、内存分析、覆盖率分析、代码运行时跟踪、性能分析和基于消息的系统测试。

2.为单一的测试环境中的宿主机和目标机进行自动化的单元测试、运行时分析。

3.自动创建和部署单元的测试桩模块和测试驱动程序。

4.绘制内存和性能曲线并对运行时追踪进行可视化显示。

5.支持代码的静态分析和基于MISRA标准的代码规则检查。

6.直接在目标机上进行测试和分析,支持所有从8位微芯片到64位RTOS。

(二)RTRT单元测试工作原理分析

RTRT单元测试工具支持C、C++、Jave和Ada语言编写的代码,提供全自动化的解决方案,大幅度提高了测试效率。分析RTRT的单元测试工作原理如下图1(以.c文件为例)。

图1显示了RTRT单元测试时测试程序经编译、链接、运行到测试报告产生的整个过程。开发人员在自动生成的测试脚本的编辑环境中根据需求开发测试用例,设计输入和预期输出。在模拟环境或目标机环境下自动运行测试程序,测试报告产生器自动生成测试报告,展示通过或失败的测试用例和代码覆盖率分析报告,发现错误可直接修改,自动进行回归测试。RTRT的变量测试包括所有的全局变量、函数间传递参数和函数返回值。RTRT基于TDP的目标机部署技术,通过对该技术进行定制可以支持全面的嵌入式目标系统,使RTRT可以同时对宿主机和目标机进行测试和调试,并对两者进行有效协调。RTRT单元测试阶段支持绝大多数项目要求的语句覆盖率、决策覆盖率、MC/DC覆盖率。

(三)基于RTRT的单元测试步骤设计

通过以上分析结合几个项目单元测试之后,我们总结了使用RTRT进行单元测试的基本步骤如下图2所示。

三、RTRT单元测试实例

以电器嵌入式软件豆浆机代码为例。目前电器产品由传统机械式控制向嵌入式的智能化控制转型,电器产品的安全也不仅限于传统的电气、电磁、机械及环境等方面,软件也成为需要检测的重点。选取豆浆机Relay单元,主要功能为继电器控制。部分代码如下:

void Relay(void)

{if(irq_r)//处理继电器动作请求

{if(lr_on)//转换继电器开

{

if(!f_lr_on)

{

f_lr_on=1;

hms3=2;//延时200ms

t2ms=0;

}

else

{

if(!hms3)//转换继电器确认打开

…………….

}

RTRT自动生成relay函数的测试例用设计模板,包含函数中出现的每个全局变量,编写上述if语句为真的测试用例,只需要编写测试输入与预期输出。如下:

VAR irq_r,init = 1,ev=init

VAR lr_on,init = 1,ev=init

VAR f_lr_on,,init=0,ev=1

VAR hms3,init=2,ev=init

VAR 2ms,init=0,ev=init

预期值与实际测试运行结果比较,生成测试报告会自动判断测试用例是否通过,可根据代码路径的覆盖要求,在测试模板中设计不同测试用例,达到需要的覆盖率,并在测试覆盖率报告中查看覆盖率百分比。为获得可靠的代码质量保证,继续根据未执行到的代码情况,编写合适的测试用例,使代码覆盖率得以提高。

四、总结

本文首先分析了嵌入式软件单元测试的基本理论,测试过程复杂,工作量较大,所以在实际的测试中,完全依靠人力确保单元测试有效实施存在困难,自动化的测试工具RTRT提供了全套自动的解决方案,自动生成测试脚本、测试程序、桩,减少了测试工作量,能自动进行回归测试,并且自动生成测试报告,以图形的形式使测试结果一目了然。不仅提高了测试效率,而且保证了测试质量。强大的TDP定制使RTRT可以支持大多数嵌入式产品的软件测试,在嵌入式领域已逐渐被广泛应用。

参考文献:

[1]蔡建平.嵌入式软件测试实用技术[M].北京:清华大学出版社,2010.

[2]姜龙,王冬星.使用IBM Rational Test RealTime进行嵌入式软件测试[J].电脑学习,2010,32(3):135-136.

[3]徐润德,陈亚,赵慕奇.基于LDRA Testbed的软件单元测试[J].海军航空工程学院学报,2011,26(3):356-360.

[4]/software/awdtools/realtime.

[5]马可.嵌入式车载电子系统软件测试方法的研究与应用[D].重庆:重庆大学,2008.

基金项目:浙江省大学生科研创新团队资助项目(编号:2012R409046);2011国家公益性质检行业科研专项资助项目(编号:201110059);2012国家公益性质检行业科研专项资助项目(编号:201210101)

单元测试方法范文第8篇

关键词:Testbed/Tbrun;软件单元测试;嵌入式软件

中图分类号:TP311 文献标识码:A 文章编号:1009-2374(2013)18-0027-02

嵌入式软件作为嵌入式系统的重要组成部分,嵌入式软件质量问题可能会带来设备的损坏和人员的伤亡,因而用户对其质量有较高的要求。软件测试是对软件质量检验的一个非常重要的手段。而软件测试中动态测试最基础的测试就是单元测试。如何开展单元测试以及如何提高单元测试的效率是一个值得研究的问题。

1 软件单元测试的要求及重点

软件单元测试是对软件基本组成单元进行测试,测试软件单元是否正确地实现规定的功能,是否满足软件性能和接口要求。并验证程序与详细设计说明的一致性。因此在单元测试时,需要模拟被测单元与其他模块之间的交互,开发驱动模块和桩模块两种辅助模块,构建一个可执行的环境,驱动模块用于模拟被测单元的上层模块,测试执行时由驱动模块调用被测单元使其运行;桩模块用于模拟被测单元在执行过程中所调用的模块。

单元测试重点考虑的测试类型有:(1) 接口测试。接口测试主要检查实参与形参的数目是否相等、实参与形参的属性是否匹配、实参与形参的单位是否一致、传到被调用模块的实参的属性是否与形参的属性匹配、是否把常量当作变量传递等内容。(2)功能测试。功能测试主要是对照软件单元的设计说明,验证软件是否完成了所需的功能。(3)重要执行路径测试。应设计测试用例以发现错误的计算、不正确的比较和不正常的控制流向等错误。在计算中比较常见的错误是:误解或错误处理算术运算的优先次序、混用不同类的操作、计算精度不够等。另外在控制软件执行流程的比较操作中比较常见的错误有:不同数据类型的比较、不正确的逻辑操作符或不正确的优先次序、因精度不够使本应相等的数不相等(如浮点数)等。(4)软件单元的局部数据结构测试。软件单元的局部数据结构是一个主要的错误来源,应设计测试用例来发现不正确的或不一致的数据说明、初始化有错或没有赋初值、不正确的变量名、不一致的数据类型、上溢/下溢或引用错误等类型的错误。(5)错误处理路径测试。一般软件错误处理路径测试应考虑下面几种可能的错误:对错误的描述不易理解、指出的错误并不是所遇到的错误、出错时还没有进行出错处理就先进行系统干预、错误边界条件的处理不正确、描述错误的信息不正确从而不足以确定出错的原因等。(6)边界测试。边界测试是检测软件在其输入/输出域、过程参数、状态转换、功能界限等具有一定范围的边界或端点条件下的运行情况,考核软件的功能或性能在其边界条件下或边界的邻近区域内是否依然满足设计要求。按照上去要求进行单元测试时,为达到要求的覆盖条件,还需采取一定的技术手段对测试覆盖率进行记录和分析,确保达到相应的覆盖率指标。采用TBrun单元级测试工具,能自动产生软件测试驱动、桩模块,提供友好的输入输出人机交互和覆盖率统计功能,能有效提高单元测试的测试效率。

2 Testbed在单元测试中的应用

使用 Testbed/TBrun的基本方法是:设计测试用例;在Testbed/TBrun中加载被测单元文件,通过Testbed/TBrun对被测软件进行源程序自动插装;根据测试用例设定输入和预期的输出,执行插装好的源程序单元;分析输入数据、预期输出和实际输出;得到被测软件在当前的测试用例执行过程中代码的覆盖率。需要注意的是,每执行一个测试用例就需要重新编译并执行。Testbed/TBrun的覆盖率统计只具有累加的功能,因此不能查询每一测试用例执行后的覆盖率信息。在执行完所有的测试用例后会生成一个总的覆盖率文件,Testbed/TBrun通过对覆盖率文件的分析得出软件单元相应语句的覆盖情况,根据这些覆盖情况可以较快确定冗余的测试数据并增补遗漏的测试数据,从而指导新的测试用例设计。在实际应用Testbed单元测试时,需注意以下三个方面:(1)数组和指针类型的变量的输入。数组可以通过在Testbed/TBrun插装后的源代码中插入数组的初始化语句对数组赋值或者在 Testbed/TBrun 环境中对数

组的一部分赋值。因指针不能被直接赋一个地址,所以输入指针可采用映射的方式来赋值,将指针变量映射成相应的自定义变量,然后对自定义变量赋值。在测试执行的过程中,这个自定义变量的值就是指针的输入值。(2)被测单元代码的必要修改。在实际的测试过程中,有的代码单元不能直接使用Testbed/TBrun直接执行测试。须在分析之前对代码单元做少量修改。如Testbed/TBrun 插装源代码时会生成 main()函数,因此被测单元中的 main()函数要改为其他的名称以避免造成名字冲突;Testbed/TBrun 执行分析时会执行被测单元,因此被测单元中的 while(1)之类的死循环结构要去掉,否则分析将无法结束。(3)模块测试后显示最终整体覆盖率,不能查询每一测试用例执行后的覆盖率信息。

3 结语

Testbed有效地支持了测试人员的测试工作,相对于完全人工测试提高了测试效率。该工具仍存在不足,还需在实践中不断完善使用方法。

参考文献

[1] TBrun Manual.pdf -Testbed7.2 help document.

单元测试方法范文第9篇

关键词:软件测试;认知误区;嵌入式;单元测试流程

1 软件测试简述

软件测试是在软件投入商用前,对软件需求分析报告、设计规格说明书和编码的最终复查,是软件质量保证的关键方法,软件测试并不等于程序测试。它贯穿于软件定义和开发的整个过程,因此,软件需求分析、软件概要设计、软件详细设计和程序编码等各阶段所得到的文档,包括需求规格说明书、概要设计说明书、详细设计说明书,以及源代码都是软件测试的测试对象。随着软件规模的不断扩大,以及软件设计复杂程度不断的提高,软件开发中出现失误或缺陷的概率越来越大。随着市场对软件质量重要性的认知程序的提高,因此软件测试在软件项目实施过程中的重要性尤为突出。软件测试将会成为一个具有很大发展前景的行业,市场将需要更多具有丰富测试技术和先进管理经验的测试技术员和项目经理。

2 软件开发项目测试的误区

软件测试从1990年左右进入中国,目前国内大的测评中心、大型企业已经完全掌握了软件测试的测试策略和测试方法。小企业普遍存在测试人员不懂什么是单元测试,怎样进行单元测试,很少能看懂代码的细节。而开发人员很少能够提供完整的详细设计报告、需求报告。导致单元测试,以拼凑测试报告为目的。

认知误区一:软件测试是软件开发的最后一道步骤,工程师们一般认为,软件实际项目要经过下面六个阶段:需求分析,概要设计,详细设计,软件编码,软件测试,软件。因而,认为软件测试只是编码后的一个孤立的阶段,这就是不了解软件测试流程的认知偏差。软件测试是一个系列的活动过程,是一个开放的体系,包括软件测试需求分析,测试计划设计,测试用例设计,执行测试。从而,软件测试应当贯穿于软件项目的整个生命周期,并不是软件开发后最后一道步骤。认知误区二:软件商用后如果发现质量问题,就武断认为是软件测试人员的工作失误。这种认识很狭隘,很是打击软件测试人员的工作积极性。软件测试只能确认软件存在错误,不能保证软件没有错误。因为从根本上讲,软件测试不可能发现全部错误,软件后的错误可能来自软件项目中的各个过程。认知误区三:软件测试对测试人员技术要求不高,任何人都可以做。很多工程师认为软件测试就是安装并运行程序,按按键盘的重复性工作。随着软件测试技术的不断改进和完善,新测试方法、新流程、新工具都在不断被开发出来。这就需要软件测试工程师掌握和学习很多专业测试新理念和新技能。认知误区四:只有编写程序的高手才是软件专家,而软件测试没有前途。由于我国软件行业整体研发能力比较低,软件开发过程不规范。不少软件项目的开发都还停留在“累加堆叠“阶段。项目开发依靠个别程序员决定,他们一人负责总体设计和代码编写,给人的印象是程序员是真正的牛人,完成了所有的软件项目开发工作。但在微软等世界知名软件企业里,软件测试人员的待遇和数量与一般程序员没有多少差异,优秀测试人员的待遇甚至比普通程序员要高的多。

3 嵌入式软件单元测试流程

单元测试是指对软件中的最小可测试单元进行检查和验证。单元是规格说明书中的最小单元,包括函数、子程序、程序。单元测试关注独立的函数功能,是测试过程中最低级别的测试活动。需要开发一个或多个测试用例执行单元测试。把代码问题缩小范围在开发阶段锁定Bug是单元测试的主旨要求,以下将介绍一种容易操作的嵌入式单元测试实战流程。

第一阶段,制定测试记录表,记录测试过程,和测试情况。测试记录表包含:源文件名,子函数名,用例标号,用例名称,用例个数,用例通过个数,语句覆盖率,分支覆盖率,MC/DC覆盖率,测试结果,问题描述,测试人员,测试时间。针对第一阶段的测试结果,此时需要大家分析出问题的代码,各抒己见,总结问题,给出解决方法。

第二阶段,解决部分测试用例failed问题,找出阻止生成用例的共性。常见问题汇总:局部变量未初始化,调用函数未声明,局部变量直接赋值,结构体嵌套、结构体指针、声明问题、声明位置问题,函数指针,大循环、死循环,绝对地址,指针变量,C语言程序中带有goto语句。解决办法:局部变量声明后,需要赋初值再使用。调用函数未声明,该问题发生在隔离测试阶段,属于代码书写不规范问题。解决方法:自定义的函数都需要在头文件中做统一声明。局部变量直接赋初值:该问题发生在测试用例无法生成阶段,属于代码书写不规范问题。解决方法,结构体局部变量,指针变量需要先声明后赋初值。结构体嵌套、结构体指针、声明问题、声明位置问题:该问题也属于代码书写不规范问题。解决方法:根据MISRA代码书写规范,结构体需要放在头文件中统一声明。大循环、死循环:单元测试需要有程序结束的出口。解决方法:把大循环改为小循环,注释掉死循环(if(1)、for(; ;),while(1))。绝对地址:单元测试不连接真实的硬件设备。遇到寄存器等绝对地址时,需要对寄存器做变量处理。指针变量:需要声明一个同类的数组,然后把数组的首地址,赋给指针变量。函数指针:需要虚构一个函数实体,取函数地地址赋给函数指针,完成映射。C语言程序中带有goto语句:需要改变程序结构,增加判断语句,去除所有的goto语句,以便确保C语言程序的稳定性。

测试第三阶段:基本圈复杂度高于MISRA阀值要求的函数,先考虑把复杂函数改为几个小函数。改不了的由开发人员写声明以及具体原因,再按照路径分支来设计测试用例。汇总测试结果,提交测试问题报告单,并提交行业标准测试报告。

4 结束语

文章简述了软件测试的基本概念,澄清了软件测试工程实践中的几个误区,依据单元测试实践的具体案例,介绍了一种高效、容易操作的嵌入式单元测试的流程。

参考文献

[1]胡丹,杜新华.基于目标机的嵌入式软件单元测试[J].电子测量技术,2006(2).

[2]赵正海,王宁.跟踪雷达“指示引导”功能软件测试方法研究[J].现代电子技术,2013(36).

[3]于园园.软件测试技术与测试管理研究[J].江苏科技信息,2016(7).

[4]王琨.嵌入式计算机软件测试关键技术探讨[J].科技创新与应用,2016(7).

[5]张金环,田洪涛.浅析设备软件测试与质量保证[J].电子工业专用备,2016,45(1).

作者简介:张军(1988-),男,陕西武功人,工学硕士,助理工程师,主要研究方向:雷达信号处理算法、数字中频收发机和嵌入式软件测试。

李攀(1987-),男,陕西西安人,工学硕士,助理工程师,主要研究方向:相控阵雷达天线技术与测试。

单元测试方法范文第10篇

【关键词】软件测试;单元测试;用例;等价类

1.软件测试

软件测试是指利用相关测试工具,按照一定的测试方案和流程对软件系统的功能和性能进行测试,对可能出现的问题进行分析、评估,发现开发错误并跟踪,以确保所开发的软件满足用户需求。软件测试是保证软件质量的主要手段,是根据软件开发各阶段的规则说明和程序内部结构而精心设计的一批测试用例,并利用这些测试用例运行程序以发现软件是否存在错误的过程,软件测试的范围应当包括更广泛些,除了考虑正确性外,还应关心程序的效率、健壮性等因素。

软件测试过程包含单元测试、集成测试、确认测试和系统测试四个步骤:

(1)单元测试:对每一个程序单元进行独立测试,检查各程序模块是否正确地实现了预定的功能。

(2)集成测试:把已通过测试的模块组装起来,对软件体系构造的正确性进行测试。

(3)确认测试:检查已完成的软件系统是否已满足了需求规格说明中的各项需求,软件配置是否完全、正确。

(4)系统测试:将经过确认的软件系统置入实际的运行环境中,与其它系统成份结合在一起进行测试。

2.单元测试

单元测试又称模块测试,是以软件系统设计的最小单位——程序模块为对象,进行正确性检验的测试工作。单元测试常被看作编码的附属品,在代码被开发、编译调试、审查后,单元测试用例设计便开始了。进行充分的单元测试,是提高软件质量,降低研发成本的必由之路。几乎所有的开发人员都会对每一段代码做一定程度的单元测试。如果一个模块要完成多项功能,可以将该模块看成由几个小程序组成,对每个小程序分别进行单元测试。如果是关键模块,往往还要做性能测试。

单元测试以详细设计说明书和源程序清单为依据,常采用白盒测试的用例,辅之以黑盒测试的用例,以寻找模块内部可能存在的错误为目的,主要完成模块接口测试、局部数据结构测试、路径测试、错误处理测试、边界测试等任务。

(1) 模块接口测试

单元测试开始时,要对通过被测模块的数据流进行测试。包括调用该模块的输入参数的正确性、调用其子模块时提供参数的正确性、全局变量的定义在各模块中是否一致等。

(2) 局部数据结构测试

包括数据类型的一致性、变量名、变量赋值、全局数据对模块影响的正确性等检验。

(3) 路径测试

对基本执行路径和循环进行测试,查找由于错误的计算、不正确的比较或不正常的控制流而导致的错误。

(4) 错误处理测试

检测对错误条件的响应是否正确,错误描述是否与实际的错误是否相符、是否能够对错误定位、是否易于理解等。

(5) 边界测试

通过设定边界值检测数据流、控制流中等于、大于或小于比较值时出错的可能性。

在面向过程编程时代,单元测试所说的单元一般是指函数,而在面向对象编程时代,单元测试所说的单元一般是指类。以类作为测试单位,测试的复杂度相对较高,所以目前通常采用的办法是为软件开发建立对应的测试工程,为每个类建立对应的测试类,为每个函数建立测试函数测试结构化的局部代码。

3.单元测试用例的设计

测试用例是指对某特定的软件系统进行测试任务的描述,它体现了测试的方案、方法和技术,包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,并形成文档。

测试用例的设计也就是测试需求细化的过程,测试需求分析和测试用例设计是密不可分的,前者是后者的依据,后者是前者的体现。测试用例的设计应与复审相结合,根据相关设计信息设计测试数据,以增大发现错误的可能性。

单元测试用例可以选取正确输入、边缘数据和错误输入作为测试数据。以系统用户注册模块中出生年、月、日的设置为例,通过等价类划分法设计测试用例。

在划分等价类时,我们将其划分为两类:1、有效等价类:是指输入完全满足程序输入的规范说明、合理的、有意义的输入数据所构成的集合。利用有效等价类可以检验程序是否满足规格说明书所规定的功能和性能。2、无效等价类:是指完全不满足程序输入的规格说明、不合理的、无意义的输入数据所构成的集合。使用无效等价类可以检验程序的容错性能。

等价类划分好之后,按以下步骤设计测试用例:1、为一个等价类规定一个唯一的编号。2、设计一个新的测试用例,使其尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步,直到所有的有效等价类都被测试用例覆盖为止,即将有效等价类分割到最小。3、设计一个新的测试用例,使它覆盖一个而且只能覆盖一个尚未被覆盖的无效等价类,重复这一步,直到所有无效等价类都被覆盖为止。

上一篇:小学语文阅读教育范文 下一篇:语文个性化教学范文