随着嵌入式系统的应用范围不断扩大,嵌入式软件的测试越来越受到重视。本文所讨论的嵌入式软件正是来源于对环境数据实时采集的无线传感器网络系统,它的目的是让远程上位机对目标环境参数实时监控。在整个系统中,它是承上启下的核心部分,具有极其重要的作用。
1系统软件的组成和工作原理
1.1无线传感器网络组成
无线传感器网络的结构如图1所示,主要由传感器采集节点和汇聚节点、数据中转器、互联网和卫星以及远端上位机组成,其主要负责采集监测环境的有关数据,如空气温度和湿度、风速、风向和降雨量等。
图1无线传感器网络结构图
根据其结构,无线传感网络软件部分以模块划分,分为网络节点软件、数据中转器、网络通信模块和上位机软件4个部分,如图2所示。网络节点软件采用的是功能化模块设计,主要负责数据采集、数据处理、数据传输和电源管理。数据中转器以ARM处理器为核心构建而成,基于μC/OSII嵌入式操作系统,它主要是通过汇聚节点和GPRS模块与节点网络和上位机通信。网络通信模块是基于LwIP和USB协议栈进行设计的,目的是实现TCP通信和USB存储。上位机软件是采用MFC界面技术设计的上层控制软件,主要是为了实现对节点网络的远程控制与数据的接收和存储。我们的研究主要是针对数据中转器的嵌入式系统软件。
图2软件模块关系示意图
1.2数据中转器的软件设计
本文研究的嵌入式数据中转器的软件模块的设计中,引入了μC/OSII操作系统。它是一个源码开放的抢占式实时操作系统,可以同时处理多个任务,并且按照任务优先级级别先后执行。它结构简单,可裁剪,可靠性高。系统大部分代码采用C语言编写,并给出了规范的接口说明,移植相当方便。这些优点能够帮助我们实现功能复杂的应用开发,使得我们合理地划分任务以及增设外部中断,实现系统高效稳定的运行以及降低系统运行功耗[1]。
本文研究的嵌入式软件测试主要是针对其中应用层的开发。
2嵌入式软件测试
2.1嵌入式软件测试的概念和特点
与普通软件不同,嵌入式软件具有专用性,它只能在需求所指定的硬件平台上运行。由于嵌入式系统的自身特点,如实时性要求高,内存不丰富,I/O 通道少,开发工具昂贵,并且与硬件紧密相关,CPU 种类繁多,其缺陷不像PC软件的缺陷容易修补等[2],使得嵌入式软件的测试较一般的软件测试困难。
在如今的嵌入式系统设计中,软件正越来越多地取代某些硬件的功能,这使得系统的成本大大降低,且可以获得更大的灵活性,然而这也加大了软件测试的工作量。因此,对日益复杂的嵌入式软件如何进行快速有效的测试成了目前一大关注的热点。
2.2嵌入式软件测试的方法
不同的嵌入式系统有着不同的测试方法,但对它们的测试仍然还存在着许多相似的问题和相似的解决方法。
按测试阶段可以把嵌入式软件测试分为需求测试、设计测试、单元测试、集成测试、确认测试和系统测试,各个测试阶段之间的关系如图3所示。
图3测试阶段关系图
单元测试: 完成对最小的软件设计单元的验证工作,只有在该基础之上才能保证后续的测试工作。找出代码单元本身的所有功能逻辑错误,具体来说,就是保证单元的最大覆盖率和检测对数据的各种分类是否考虑全面,处理是否正确。主要采用白盒测试技术。单元测试一般可以就在宿主环境上运行。
集成测试: 把经过单元测试的模块按软件的结构组合在一起作为一个系统或一个子系统来综合测试。主要是用来发现程序的架构和体系结构设计方面的错误。这其中主要还是白盒测试,黑盒测试作为辅助。集成测试一般是在宿主环境中进行。
确认测试: 把软件系统作为一个单一的执行实体进行需求测试。其目的是验证软件是否满足所有的功能、行为和执行要求,这部分主要是用黑盒测试。
系统测试:将系统的测试软件系统和其他资源都综合起来进行测试。是用来确保整个系统的性能、执行强度、安全性和功能都达到了预期的要求。所以在这个阶段要和硬件结合,即在目标环境中进行。
2.3嵌入式软件测试的关键技术
2.3.1代码隔离
为了提高效率,应该一次性将一位工程师负责的测试任务隔离出来。隔离时,应把源文件分为3类:被测文件、外围文件、其他文件。被测文件是测试目标,外围文件是指与被测文件关联密切的底层或相关文件,这些在测试时最好直接调用实际代码,减少打桩造成的失真,其他文件则完全隔离。
2.3.2插桩技术
插桩技术是动态测试中一种基本的测试手段,主要借助向源程序中添加一些语句,通过对程序语句的执行、变量的变化等情况进行检查,来实现测试目的[3]。插桩时需要在被测试的源程序中植入插桩语句,而插桩语句的原型在插桩函数库中定义,在目标文件连接成可执行文件时,必须连入插桩函数库。探针函数是否被触发取决于插桩选择记录文件,要求不同的覆盖测试激活不同的插桩函数。因此插桩技术的关键包括要探测哪些信息、程序中什么部位设置探针、如何设计探针,以及探针函数捕获数据的编码和解码。插桩的典型实现方式如图4所示。
图4插桩的典型实现方式
实施插桩的步骤如下:
① 将被测程序经过预处理展开为不包含宏、条件编译和头文件的文件格式,如果测试的源代码是会变的,还要将短跳转改为长跳转。
② 按照一定的插桩策略将探针函数加载到预处理后的文件中。方法是将程序划分成“块”,探针主要插在其“路口”的位置。
③ 制作插桩库,主要是生成插桩库中的探针函数。
④ 将编译生成的目标文件与制作插桩库时生成的库文件链接起来,生成带有插桩信息的可执行程序。
⑤ 运行程序,通过插桩点来获取信息。
2.3.3底层模拟
模拟对象是解决内部输入的一种方法,不过对于C++,尤其是C语言,这种方法比较麻烦,增加大量的额外工作,也不能解决静态输入、中断输入、难于实时化。比较便利的方式是底层模拟。模拟对象的工作原理是替换对象,底层模拟的工作方式是控制函数,即直接控制函数的行为,对C和C++同样适用。对于静态输入和中断输入,由于没有函数调用或函数调用不确定,可以用自动修改被测试代码的方式调用自动生成的函数来实现控制。
3数据中转器测试系统结构图
嵌入式软件测试其实是嵌入式软件开发过程中的重要环节,也是嵌入式软件从开发到应用的关键一环,图5给出了嵌入式软件的统一测试模型。嵌入式软件与普通软件不同之处在于嵌入式软件测试有宿主机环境测试和目标机环境测试之分。
图5宿主机环境下的单元测试
由于在宿主机环境下可以方便、迅速地进行测试,同时便于修改,因此本系统的单元测试主要在宿主机环境下进行。宿主机环境下单元测试与普通软件的单元测试原理是相同的。
对于嵌入式软件的测试有一个共同的问题:测试工具运行在宿主机上,测试所需要的信息在目标机上,并通过一定的物理/逻辑连接传输到宿主机上,由测试工具接收。因此,测试系统的覆盖测试需要建立宿主机与目标机之间的物理/逻辑连接,以解决数据信息的传输问题。其中覆盖测试的基本原理如图6所示。
图6嵌入式软件覆盖测试原理图
4主要软件测试工具
LOGISCOPE是嵌入式软件测试工具集。它贯穿于软件开发、代码评审、单元测试、集成测试、 系统测试以及软件维护阶段。它面向源代码进行工作,针对编码、测试和维护。因此,LOGISCOPE主要应用于代码评审和动态覆盖测试。
LOGISCOPE工具的最大优点就是能同时支持宿主机上和目标机上的覆盖测试,这是因为LOGISCOPE提供了运行在目标机上的程序代码,其中包括:
① 1个用来收集和发送覆盖信息的主循环线程,该线程即是嵌入式应用中的特殊任务。
② 实现具体数据传输的函数,包括对串口或网络的驱动,它们将被上述线程调用。
③ 插桩函数的实现,这些函数被被测代码调用,向缓冲中放入覆盖消息块。
④ 对缓冲信息队列的管理。
⑤ 初始化代码。
在嵌入式软件测试中,使用LOGISCOPE测试工具,确保系统易于维护,减少风险。LOGISCOPE的使用能够在最短的时间内提高软件的质量和效率。
5总结
尽管嵌入式软件测与普通软件测试有诸多不同,但其目的都是尽早发现软件中的 Bug 并反馈给程序开发人员以便及早修正、改善软件质量。本文对实时嵌入式软件的进行了研究,介绍了嵌入式软件测试的实现策略。试验证明,该策略方案稳定可靠,适用于无线传感器网络。