“模块(Module)”这个术语可能更适合于这样一个协作单元集合,但我更喜欢用“组件(component)”这个术语,因为它的含义与C/C++源模块不一样。
“组件”内含的“单元”中,必须至少有一个具备从组件外部调用以驱动组件的功能。通常一个组件的几个单元来自外部调用,我们称这些单元为“组件函数”或“组件单元”。对一个组件的测试不再由(一个或多个)对单个单元的调用(如上面两部分所述)组成,而是由对(不同的)组件单元的一系列调用组成。对组件单元的调用将激活组件,与单个单元测试一样,组件的测试用例也包括输入和输出数据(组件的变量和被调用组件单元的参数)。组件可能具有内部单元,这些单元不能从组件外部调用,只能通过组件内部的函数调用获取。
内部单元所做的工作(如果有的话)与组件测试无关,因此组件测试中,是将整个组件看作一个黑盒。然而,与组件测试结果相关的是从组件内部到其他组件中(可调用的)单元的调用序列。这涉及到调用的数量、调用的顺序和调用传递给其他组件的参数。
很显然,组件中单元的功能以及它们之间的接口大部分情况下是通过组件测试来实现验证。因此,组件测试可以看作是对组件中单元的集成测试。
♦ 1.1.4 相互作用且有时序关系的单元
在上一节中,时序不是重点,无论是组件的激发调用时长,还是组件的激发调用与另一个组件的结果调用之间的时长。然而,这是一个检查收到激发调用后响应是否足够快的重要测试,即在给定的时间范围内。
为了能够在模拟环境中测试组件的时序行为,需要有一个模拟的时间基数。这意味着组件内部的某个单元在已知的等距时间内被调用(例如每10ms),通常组件在实时操作系统(RTOS)的控制下执行并使用time-slicing(例如OSEK)就是这种情况,但一个简单的中断驱动应用程序通常也符合这种要求。
对该单元的调用代表组件的“心跳(heartbeat)”,它们为测试组件的时序行为提供了一个(模拟的)时间参考。心跳函数通常被称为“handler function”或“work task”或简单称为“tick”。
Fig.4 如果心跳函数存在,则可以测试时序行为
2 C++栈的例子
• 2.1 介绍
正如前面所介绍的,抽象数据类型栈是一个典型的例子,在Tessy中进行集成测试需要使用Tessy的组件测试功能(在场景编辑器透视图中可以访问)来完成。而且,push和pop不相互调用,而是在公共数据(栈)上通信,因此,单纯的单元测试技术手段是不适用的,因为它们要求单元有一个单一的入口点,即单元测试侧重测试一个单一函数/方法。
Fig.5 stack.push和stack.pop不互相调用,需要集成测试
• 2.2 测试对象源代码
Fig.6 测试对象的源码(stack.cpp)
注:源代码最后三行不属于堆栈的实现,而是Tessy所要求的,由于使用了#ifdef,所以tick()函数只在源文件被Tessy处理时才出现。
• 2.3 Tessy准备工作
测试环境选择GCC(C++),测试类型选择Component,导入代码。
Fig.7 选择编译环境
新建一个变量my_stack作为实例化的对象。
Fig.8 接口设置
创建第一个测试用例:验证入栈出栈操作。
Fig.9 场景1的设计和执行结果
创建第二个测试用例:该用例目的是验证栈下溢情况下的功能实现。
在Edit Test Execution Settings界面勾选Test Cases Separately分别执行两个场景,场景及结果如下图所示。
Fig.10 场景2的设计和执行结果
在SCE的用例设计界面中,针对指针的操作如下:为指针*arr创建一个对象,指定其为一个长度为4的数组;指向这个目标的指针由Tessy分配给对象my_stack中的变量arr,也就是说,分配的内存代替了由测试对象的构造函数分配的内存,由于此前将指向指针对象的接口设置为INOUT,所以该对象同时出现在Inputs和Outputs列项中。
Fig.11 为指针*arr创建一个对象
Fig.12 场景2 SCE执行实际结果