1.每个函数只完成单一的功能。
单一功能的函数容易理解,也容易预测其行为。测试的时候,给定一些输入数据就知道它的输出和影响,易于测试。
2.把函数分为查询和命令两类。
查询函数只查询对象的状态,而不改变对象的状态。命令函数则只修改对象的状态,只返回其操作是否成功的标志,而不返回对象的状态。
3.验证输入数据,确认使用者正确的调用了函数。
assert检查仅用于debug版本。
c++与JAVA可以用throw抛出异常。
c就不行了。
但是,检查过参数后可以打印一个警告。仿照glib:
return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
需要定义两个宏,一个用于无返回值的函数,一个用于有返回值的函数:
#define return_if_fail(p) if(!(p)) /
{printf("%s:%d Warning: "#p" failed./n", /
__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) /
{printf("%s:%d Warning: "#p "failed./n",/
__func__, __LINE__); return (ret);}
这样一来,遇到无效参数时,可以看到一个警告信息,同时又不影响测试。
4.在测试时,用查询来验证命令。
命令一般都有返回值,但只检查返回值是不够的。
应该使用查询函数来检查对象的状态是不是预期的。
比如,删除一个节点后,删除函数会返回一个成功标志,但是,为了更保险,可以使用断言之类的调试中使用的警告语句,进行一下状态查询,看结果是不是真正执行了。
5.使用基本查询区验证符合查询。
比如,一个矩形对象的复制,可以再使用分别检验长宽的方法来验证成功地复制了矩形。
6.预测结果依赖其执行上下文,要按逻辑组织测试用例。
为了简化测试,在每组测试用例开始时,都要重置对象到初始状态。
7.第一次只写基本的测试用例,以后逐渐积累,每次发现新BUG就把相应的测试用例加进去。每次修改了代码就运行一遍自动测试,保证修改没有引起其他副作用。
好的测试,可以减少调试的时间,是在调试之前的又一道保障!!生命啊