7.1 准备测试代码、测试用例
(1)编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)
(2)在进行集成测试/ 系统联调之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。好的测试用例应尽可能模拟出程序所遇到的边界值、各种复杂环境及一些极端情况等。
(3)在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。程序的调试与测试是软件生存周期中很重要的一个阶段,如何对软件进行较全面、高率的测试并尽可能地找出软件中的错误就成为很关键的问题。因此在编写源代码之前,除了要有一套比较完善的测试计划外,还应设计出一系列代码测试手段,为单元测试、集成测试及系统联调提供方便。
7.2 使用断言来发现软件问题,提高代码可测性
(1)断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。
示例:下面是C语言中的一个断言,用宏来设计的。(其中NULL为0L)
#ifdef _EXAM_ASSERT_TEST_ // 若使用断言测试
void exam_assert( char * file_name, unsigned int line_no )
{
printf( "\n[EXAM]Assert failed: %s, line %u\n",
file_name, line_no );
abort( );
}
#define EXAM_ASSERT( condition )
if (condition) // 若条件成立,则无动作
NULL;
else // 否则报告
exam_assert( __FILE__, __LINE__ )
#else // 若不使用断言测试
#define EXAM_ASSERT(condition) NULL
#endif /* end of ASSERT */
(2)用断言来检查程序正常运行时不应发生但在调测时有可能发生的非法情况。
(3)不能用断言来检查最终产品肯定会出现且必须处理的错误情况。断言是用来处理不应该发生的错误情况的,对于可能会发生的且必须处理的情况要写防错程序,而不是断言。如某模块收到其它模块或链路上的消息后,要对消息的合理性进行检查,此过程为正常的错误检查,不能用断言来实现。
(4)对较复杂的断言加上明确的注释,澄清断言含义并减少不必要的误用。
(5)用断言确认函数的参数。示例:假设某函数参数中有一个指针,那么使用指针前可对它检查,如下。
int exam_fun( unsigned char *str )
{
EXAM_ASSERT( str != NULL ); // 用断言检查“假设指针不为空”这个条件
... //other program code
}
7.3 版本控制
(1)正式软件产品中应把断言及其它调测代码去掉(即把有关的调测开关关掉),加快软件运行速度。
(2)在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响——即有测试代码的软件和关掉测试代码的软件,在功能行为上应一致。
(3)用调测开关来切换软件的DEBUG 版和正式版,而不要同时存在正式版本和DEBUG 版本的不同源文件,以减少维护的难度
(4)软件的DEBUG 版本和发行版本应该统一维护,不允许分家,并且要时刻注意保证两个版本在实现功能上的一致性。