基于cunit的自动测试框架

摘要:随着现代软件工程的发展,软件质量的要求逐渐得到提高,而软件测试也因此受到越来越多的重视。在企业级应用领域,以xunit为代表的自动测试框架已经趋于成熟。但是在嵌入式系统开发领域,由于软件系统对硬件平台的依赖,软件在通用性和易测试性方面都比较欠缺,从而导致自动测试系统的贫乏。本文分析说明了软件测试的作用,特别是在嵌入式开发过程中的作用,以及实施软件测试所需要的代价。基于以上理论,本文论述了一个基于cunit设计的自动测试框架。鉴于自动测试系统对测试工作的重要性,模仿xunit的特性,对cunit进行了改进。并且针对嵌入式系统的特性,在框架中加入了守护线程,用以模拟中断等外部事件。

关键词:cunit; 测试框架;自动测试;测试包;多线程支持

中***分类号:TP311文献标识码:A文章编号:1009-3044(2007)18-31631-03

Unit Test Framework Based on Cunit

LIU Bo

(College of Software Engineering,Southeast University,Nanjing 210096,China)

Abstract:unit test framework like xunit is widely used in enterprise application, but seldom in embedded system because different hardware architectures have different requirements. This paper demonstrated a unit test framework based on cunit, which could be used to test a large part of a embedded system, and discussed how to use it to improve the quality of the software while keep the cost low.

Key words:cunit;unit test framework;test suite; multi-threaded

1 引言――测试与自动测试系统

随着现代软件工程的发展,软件测试做为软件质量保证的最重要手段之一,越来越受到重视,如何有效迅捷的进行测试,也成为了业界讨论的重点。

在企业级应用(enterprise application)领域,以xunit为代表的自动测试技术已经趋于成熟。实践证明,自动测试技术,特别是采用了测试驱动开发模式的自动测试技术,可以很大程度的改善软件质量,而且实施的代价也是可接受的。

但是在嵌入式系统开发领域,实施自动测试的代价相对来说就大了很多。由于软件系统对硬件平台非常依赖,测试通常都是在真机或者是模拟器上进行,而这种测试即为手动测试,效率是相当低下的。而如果采用做桩的模式对系统进行自动测试,那么创建桩的工作量又非常的大,其代价是不可以接受的。

因此,现存的针对嵌入式系统,或者针对c的自动测试框架几乎没有。但是我们认为,正是由于嵌入式系统测试很难实施,单元测试就更加重要。而对于手动测试和自动测试,可以进行动态的选择。首先,软件系统的设计必须是松耦合的模块化设计。之后,根据各个模块的特性进行分析――对硬件平台依赖比较大的,进行手动测试;对硬件平台依赖比较小而自身逻辑比较复杂的,做桩进行自动测试。

所以,我们需要一个简单但是完善的自动测试框架系统。通过调研,我们最终决定采用开源系统cunit,将其扩充改进成我们所需的框架。

2 Cunit及其工作原理

cunit是一个开源软件,基于zlib/libp许可证, 作者是Asim Jalis。可以在sourceforge上找到该项目。本文采用的是1.4版本。

该版本的cunit的运行环境是linux,因为其利用了linux的bash的一些功能。

cunit的工作原理是,利用bash的grep功能,搜索当前目录下所有.c文件中的void Test***(CuTest *tc){...} 形式的函数,其中***表示可以用任意字符替代。然后,将所有这些测试函数集中起来,生成一个带有main的.c文件。对所有文件进行编译链接后运行,即会逐步调用所有的void Test***(CuTest *tc){...} 函数,完成自动测试。

测试结果默认会输出到控制台上,当然还可以用bash的重定向功能输出到指定文件中去。

cunit提供了一批类xunit的assert函数。函数原型为void FunctionName(CuTest* tc,…)。其中,FunctionName是函数名称,在其头文件中有定义;tc是一个框架需要的指针,其参数值就是Test函数中的参数tc。在实际使用中只需要直接赋值就可以,框架会使用它的。

这些assert函数的作用是,断言当前条件是否为真。断言方式由函数功能定义,如比较两个字符串是否相等,两个整数是否相等之类。

一旦断言为真,则继续执行。当某个Test函数成功执行完毕,则算通过了一个test。

一旦某个断言为假,则直接跳出这个Test函数(利用longjmp功能),并记录一个test fail。

该断言机制与xunit是一致的。

3 基于cunit的进一步设计

cunit实现了最基本的单元自动测试功能,并且封装了比较好的字符串处理功能以提供友好的用户界面(尽管只是字符界面)。但是,相对于我们的需求,他还是有一些欠缺的地方。下面就对cunit进行一些改进,以实现xunit具有的一些特性。

3.1Startup 和 Teardown

每一个Test函数就是一个测试用例。在xunit中,有StartUp和TearDown功能,用来在每个测试用例测试之前建立环境,测试完毕之后清除环境。我们在cunit上做改进以实现这种功能。

首先,打开cunit的头文件CuTest.h,找到结构体CuSuite的定义。我们在之前定义两个函数指针类型:

typedef void (*StartUpFunc)();

typedef void (*TearDownFunc)();

接下来在CuSuite的定义中,添加两个函数指针变量,分边指向用户定义的StartUp和TearDown函数(斜体为新添加部分):

typedef struct

{int count;

CuTest* list[MAX_TEST_CASES];

int failCount;

StartUpFunc startUp;

TearDownFunc tearDown;

} CuSuite;

再打开CuTest.c,找到函数CuSuiteRun的定义,做如下更改(斜体为新添加部分):

void CuSuiteRun(CuSuite* testSuite)

{int i;

for (i = 0 ; i < testSuite->count ; ++i)

{/*在每个测试用例测试前,建立环境*/

本文为全文原貌 未安装PDF浏览器用户请先***安装 原版全文

if(testSuite->startUp != NULL)

{(testSuite->startUp)();

}

CuTest* testCase = testSuite->list[i];

CuTestRun(testCase);

if (testCase->failed)

{

testSuite->failCount += 1;

}

/*在每个测试用例测试结束后,清除环境*/

If (testSuite->tearDown != NULL)

{

(testSuite->tearDown)();

}

}

}

这样,在每个测试用例运行的前后,都会自动运行StartUp和TearDown了。

当然,由于StartUp与TearDown都是由用户提供,我们还需要对自动生成脚本make-tests.sh做修改:

添加如下的外部函数声明,注意声明的类型需与CuTest.h中定义的两个函数指针一致:

extern void StartUp();

extern void TearDown();

这样声明后,链接时链接器会去寻找这两个函数的定义。如果用户未提供定义,则链接无法通过。

再在RunAllTests函数中,对CuSuite结构suite的两个函数指针赋值(斜体为新添加部分):

void RunAllTests(void)

{ CuString *output = CuStringNew();

CuSuite* suite = CuSuiteNew();

suite->startUp = StartUp;

suite->tearDown = TearDown;

……

注意,该函数存在于make-tests.sh中,在创建测试包的时候被自动生成。

这样一来,StartUp和TearDown功能就被添加到cunit框架中去了。

值得注意的是,StartUp和TearDown功能是添加到测试包中的,而非添加给测试用例。测试包的概念是一组相似的测试用例,而且这组测试用例具有相同的运行环境。

3.2与项目的整合

cunit所建立的测试系统是测试包,但是我们所需要的实际上是若干个测试包,以对应软件系统中不同的软件模块。这里,我们不再修改cunit,而是利用软件系统的文件结构和linux的bash所提供的一些功能,自动调用每个模块所对应的测试包,再将测试结果自动整合。

如***1所示,我们通过树形文件结构将cunit以及所有的测试用例与项目源码整合在了一起。在一个硬件芯片上,通常会有15%的元件做为测试单元存在。软件系统也是一样,测试用例是属于源代码的一部分存在于系统之中的。

***1 整合了测试的项目构架

Src下是项目的源码,其下分成了若干模块。

Inc是项目源码对应的头文件。

Test下是所有的测试用例。如上***所示,测试用例与项目源码具有一一对应的关系,结构上也同样对应。

Util存放了一些工具,如cunit等。(是的,cunit和测试代码可以分开的,因为我们有make)

首先,如***1,在合适的位置建立测试包。每个测试包包含其自身的测试用例,测试用例需要用到的桩,以及一个make文件去定义测试所需要包含的项目源文件以及工具文件。

而后,在Test根下建立一个bash脚本,遍历所有的测试包,对每个包进行编译?链接?测试,并将测试结果放置在测试包下的一个记录文件中。

最后,从所有的测试包中取出记录的测试信息,整合以后提供给用户。

如此一来,一个自动测试框架就建立好了,可以方便的执行测试先行开发。如果不需要每次都对所有的测试包进行测试,简单修改bash脚本就可以了。

4 高级功能:多线程的支持

嵌入式系统虽然很少有并发计算的需要,但是由于其与硬件的联系非常紧密,会有另外一种形式的并发发生:中断。

中断当然无法用桩来模拟,因为桩只是提供一些假的接口,返回正确或错误的值(实际上,桩返回错误值更有意义,因为这样可以检验模块内部处理错误情况的正确性,而无需人为的创造错误条件),它不可能主动发起某个动作。

理论上来说,中断也是不可以用多线程来模拟的,因为其工作原理不一样。有很多中断也无法用多线程来模拟,如EEPROM和UART的读写(慢速IO设备,利用中断实现异步读写)。不过,还是有很多情况下,中断事件是可以通过多线程来模拟的,比如某个计时器的触发,某个外部传感器的值更新等。这些情况下中断仅仅是更新某个全局变量,或者是调用某个简单的函数,完全可以用多线程来模拟,并且这种模拟很有价值――与系统的运行逻辑紧密相关。比如,某个逻辑模块需要检测系统上某一传感器的值,当其发生变化时,通过LED或其他方式做出相应的反应,测试该逻辑模块时,就需要一个辅助线程来改变传感器的值。

因此,我们设计了一个StubThread模块,放在系统的util目录下,来提供多线程的支持。多线程的实现基于兼容于posix的pthread。该模块的功能是,创建n个线程,其中n为用户定义的线程数。每个线程在经过某一指定的时间后,调用相应的回调函数(即触发事件)。每个线程都可以被***地开关。

StubThread.h:

#ifndef _STUB_THREAD_H

#define _STUB_THREAD_H

/*回调函数指针*/

typedef void (*CallBackFunc)();

typedef enum{

TRUE = 1,

FALSE = 0

}BOOL;

/*线程数据结构体*/

typedef struct{

BOOL active; /*是否触发事件。*/

double delay; /*每两次事件的时间间隔*/

CallBackFunc callee;/*回调函数指针*/

}STUB_SEM;

extern STUB_SEM * pStubSem;

extern const int StubSemLength;

void StartStubThread();

void StopStubThread();

#endif

使用该工具的客户代码需要提供pStubSem和StubSemLength,前者指向一个STUB_SEM类型的数组,后者标识该数组的长度。

STUB_SEM中,active表示该事件是否会发生,delay表示每两次该事件发生的时间间隔,callee则是当该事件发生时,事件响应函数的指针。

若active被置为true,则事件会被周期性的触发。若只希望该事件被触发一次,则可在响应函数中将active设置为false。

callee指向的相应函数是桩提供的,该响应函数根据实际需要,伪造数据或触发事件。

以下是StubThread模块的实现(zlib/libp并没有要求公开修改后的源码)。

StubThread.c:

#include "StubThread.h"

#include

tspec.省略_sec) * nanoFactor);

nanosleep(&tspec, NULL);

}

/*线程方法。每个线程都运行该方法。方法结束时相应的线程也会结束*/

void ThreadFunction(STUB_SEM *sem){

while(running){

if(sem->active){

stWait(sem->delay);/*等待指定的时间*/

(sem->callee)();/*调用回调函数*/

}

}

}

/*此方法将启动所有辅助线程*/

void StartStubThread(){

int ret,i;

/*start thread:*/

running = TRUE;

for(i=0;i

ret = pthread_create(&(pthreadIDs[i]), NULL, (void*)ThreadFunction,&pStubSem[i]);

if(ret!=0){/*如果发生错误*/

running = FALSE;

printf("Create pthread error!n");

exit(1);

}

}

}

/*此方法将终止所有线程*/

void StopStubThread(){

int i;

/*set semaphore to stop it:*/

running = FALSE;

/*wait for stop:*/

for(i=0;i

pthread_join(pthreadIDs[i],NULL);

/*reset*/

pthreadIDs[i] = 0;

}

}

用StartStubThread后,会为每个STUB_SEM开启一个***的线程。而调用StopStubThread后,会把所有的线程终止掉。

STUB_SEM中的active做为信号量实现线程间通讯。

5 结论

经过实际项目的使用,该自动测试框架运行正常,用较低的代价保证了软件质量,对于逻辑比较复杂的模块是相当有效果的。但是由于创建桩的成本比较高,并且某些中断事件用该框架提供的模型模拟并不可靠,选择哪些模块使用该框架测试是非常重要的。选择的主要依据是逻辑较复杂且对特定的硬件功能(如数模转换,UART等)无依赖。

在实际项目中,我们仅将逻辑层用这套自动测试工具进行了测试。逻辑层之上的应用层与用户交互非常频繁,所需做的桩很多,不合适。而底层与硬件关系非常紧密,逻辑简单,但需要在真机上实测。

最终,项目的测试时间比依据经验估计的时间缩短了近四分之一(包括写测试用例与测试桩的时间,但不包括设计实现本测试框架的时间)。实践证明,嵌入式系统的开发也可以应用自动测试技术。在合理选择测试范围的情况下,软件系统的质量与测试效率可以得到较显著的提高。

参考文献:

[1]H ZHU,PAV HALL,JHR MAY.Software Unit Test Coverage and Adequacy[M].ACM Computing Surveys,1997.

[2]Paul Hamill.Unit Test Frameworks[M].O'reilly,2004.

[3]J.Ramsey,V. Basili.Structural Coverage of Functional Testing [R].Proceedings of the IEEE 8th International Conference on Software Engineering,1985-08.

[4]Kent Beck,Test Driven Development: By Example [M].Addison-Wesley Longman,2002.

[5]Bel Lewis,Daniel J.Berg,Pthreads Primer: A Guide to Multithreaded Programming [M].SunSoft Press,1996.

注:本文中所涉及到的***表、注解、公式等内容请以PDF格式阅读原文。

本文为全文原貌 未安装PDF浏览器用户请先***安装 原版全文

转载请注明出处学文网 » 基于cunit的自动测试框架

学习

羽毛球扣球技术分析

阅读(36)

本文为您介绍羽毛球扣球技术分析,内容包括羽毛球扣球慢动作gif,羽毛球如何接别人的扣球。摘要羽毛球是一项深受人民群众喜爱的体育项目,在社会群体与学校群体中都十分受欢迎。羽毛球在运动过程中具有一定的娱乐性、趣味性,人们可以在进行

学习

浅析农民工进城对农村的影响

阅读(104)

本文为您介绍浅析农民工进城对农村的影响,内容包括农民工进城落户农村土地要收回吗,农村农民工进城打工。【摘要】随着城市化进程的不断推进,越来越多的农民工从乡村进入城市,为城市建设作出了巨大贡献。然而,随着社会竞争的加剧,对农民工的

学习

紫砂水仙盆收藏与赏鉴

阅读(21)

起紫砂,人们首先想到的是紫砂茶具。其实除茶具之外,宜兴产的其他紫砂器物,如碗、碟、罐、盂、盆、洗等也很有特色。在这些产品中,有一种小巧玲珑、造型别致的水仙盆,特别深受人们的喜爱。在《简明陶瓷词典》一书中把水仙盆列为洗类,“洗,陈设瓷

学习

壮志凌云(4)

阅读(22)

本文为您介绍壮志凌云(4),内容包括壮志凌云女主角,壮志凌云电影解说。一线人员的成长道路终端争夺的实战记录第四篇优化春节节刚过,一直忙忙碌碌的凌云特有成就感。所有的促销活动都开展顺利,据初步统计,近几日的销量几乎相当于平时1个月的

学习

不可替代作文500字

阅读(21)

谁的心中都没有一个不可替代的人吧。我也不知道是否心中有个不可替代的朋友,但我深知,家里人绝对不可替代。只是还是没有找到一个不可替代的朋友。因为我会把一件事同时分享给不止一个人,那在我心中大概他们都是可以信任的,都是我的不可替代

学习

企业岗位创新工作绩效考核管理

阅读(32)

本文为您介绍企业岗位创新工作绩效考核管理,内容包括关于组织绩效考核的管理创新课题,绩效考核创新项目计划表。在当前这个经济快速发展的信息时代,各企业要想在竞争激烈的市场中占据一席之地,获得良好的发展,就必须要提高企业内部的创新能

学习

罗马圣彼得大教堂的诞生

阅读(17)

本文为您介绍罗马圣彼得大教堂的诞生,内容包括罗马圣彼得大教堂是谁的作品,罗马大教堂和圣彼得大教堂。著名的《圣经》中写道:“你是彼得,我要在这块石头上建造我的教堂。”这句话本意是支持教皇至上的权威,但也同样适用于罗马圣彼得大教堂

学习

737NG飞行扰流板故障浅析

阅读(43)

文章主要结合作者日常实际工作探讨737NG飞机出现的飞行扰流板故障的产生原因和排故方法。关键词:扰流板;钢索;校装;滑轮英文关键词:737NG;SPOILER;ADJUST1.排故过程737NG飞机近期出现单侧飞行扰流板在收起位与后缘襟翼有较大间隙故障,初次

学习

从伦勃朗的《圣家族》解析“伦勃朗的强烈色彩”

阅读(16)

本文为您介绍从伦勃朗的《圣家族》解析“伦勃朗的强烈色彩”,内容包括伦勃朗开始大量运用阴郁色彩,伦勃朗光线。“伦勃朗的强烈色彩”是马克思、恩格斯在一篇书评里谈到艺术描写生活的真实性问题时提出的,作为艺术创作的原则,有着丰富的美

学习

素数的分布有规律性

阅读(20)

本文为您介绍素数的分布有规律性,内容包括素数分布规律及其特性,素数的分布规律。【摘要】文章中首先引入L等差数列组集合的概念,把素数分布范围压缩到L等差数列组集合中来,以便研究素数分布的规律性;并推导出素数的个数公式和素数分布的规

学习

古笛复原研究

阅读(25)

本文为您介绍古笛复原研究,内容包括上古古笛有什么用,亡灵序曲古筝教程。引言贾湖骨笛是迄今为止我国历史上最早、形态完整、现今仍可演奏的吹管乐器,是距今9000~7500年前中国古代音乐文明最重要的实物载体之一。1999年,经中国科技大学科技

学习

机组资源管理的五个关键字

阅读(17)

本文为您介绍机组资源管理的五个关键字,内容包括机组资源管理发展史,crm机组资源管理系统。机组资源管理(CREWRESOURCEMANAGEMENT)并不是一个新概念,它是人们对现代航空历史中出现的各种事故加以总结和研究,并且对人的因素加以分析,最终产生

学习

安全感:我们要给孩子做一个“摔得容易”

阅读(26)

〔关键词〕安全感;“摔得容易”;心理环境面对可能的失败,孩子们会选择果断地冲上去,还是因为担心结果而选择拒绝挑战?一次失败后,孩子们会选择再挑战一次,还是因为背负羞愧而选择退缩?如果孩子们常常选择拒绝或退缩,这是为什么?在《还珠格格》里有

学习

黄飞鸿故里光大武术文化

阅读(29)

近半个世纪以来,黄飞鸿这个名字早已蜚声海内外。以他为原形创作的影视作品就有100多部,其中已故香港艺人关德兴师傅亲自扮演和拍摄黄飞鸿的影视集就有77部;武打巨星成龙、李连杰、赵文卓等亦演绎过黄飞鸿的绝世风采,黄飞鸿已成为了中华武术

学习

变电站综合自动化系统的现状与发展

阅读(26)

本文为您介绍变电站综合自动化系统的现状与发展,内容包括变电站综合自动化现状及前景分析,变电站综合自动化实训报告。在当今企业的发展中,供电系统日益增大,满足各类装置的用电需要是供电系统要实现的目标。针对这种情况,电力系统的发展和

学习

配网自动化及其三遥功能的实现探讨

阅读(14)

本文为您介绍配网自动化及其三遥功能的实现探讨,内容包括配网自动化通讯有哪几种方式,三遥自动化终端。配电自动化在我国兴起的时间较短,主要是因为人们生活水平的不断提高对电网的要求也更高了,相关的配电部门为了满足用户的需求,在工作中

学习

探析软件测试之系统测试

阅读(34)

本文为您介绍探析软件测试之系统测试,内容包括软件测试的系统测试范畴,软件测试接口测试相关知识。摘要:系统测试在软件测试中占有非常重要的地位,本文对系统测试的概念、系统级功能测试技术及系统测试的主要内容进行了简单阐述,同时对几种

学习

电气自动化控制系统分析

阅读(26)

本文为您介绍电气自动化控制系统分析,内容包括电气自动化控制系统设计流程,电气自动化考研哪个方向最好。摘要:文章通过分析当前电气自动化系统的功能,论述电气自动化控制系统的设计思想,展望了将来电气自动化控制系统的发展趋势。

学习

软件测试工作总结

阅读(26)

本文为您介绍软件测试工作总结,内容包括软件测试年度总结,软件测试员工作总结。2012年10月9日,我怀着对提高并实现自我价值的心态,跨进西安三茗科技有限责任公司的大门,开始了自己大学里兼职实习工作。转眼间,断断续续的三个星期的实习时间

学习

普通话测试应试技巧

阅读(25)

本文为您介绍普通话测试应试技巧,内容包括新编普通话应试教材,普通话应试时间。读单音节字环节限时3.5分钟。读错一个字扣0.1分,读音有缺陷扣0.05分。应试人发觉第一次读音有口误时可以改读,按第二次读音评判。满分10分。

学习

解读体能测试

阅读(70)

本文为您介绍解读体能测试,内容包括警察体能测试标准,警察体能测试。体能测试是健康体检的新型项目,是在一般的生理、心理检查项目之外对身体运动能力的进一步检查。目前在健康体检中心相继开展。

学习

电气工程及其自动化

阅读(24)

本文为您介绍电气工程及其自动化,内容包括考研电气工程及其自动化,电气工程及其自动化招聘。摘要:随着全球信息化、智能化时代的到来,我国也追随着科技与时展的大潮,大步跨前的迈向时代的前沿,而信息技术化的发展与延伸已经深深推动电气工程