一个好的设计应能预见各种出错条件,并预设各种出错处理通路,出错处理通路同样需要认真测试,测试应着重检查下列问题:

  1输出的出错信息难以理解;

  2记录的错误与实际遇到的错误不相符;

  3在程序自定义的出错处理段运行之前,系统已介入;

  4异常处理不当;

  5错误陈述中未能提供足够的定位出错信息。

  边界条件测试是单元测试中后,也是重要的一项任务。众的周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。

  单元测试过程

  一般认为单元测试应紧接在编码之后,当源程序编制完成并通过复审和编译检查,便可开始单元测试。测试用例的设计应与复审工作相结合,根据设计信息选取测试数据,将增大发现上述各类错误的可能性。在确定测试用例的同时,应给出期望结果。

  应为测试模块开发一个驱动模块(driver)和(或)若干个桩模块(stub),下图显示了一般单元测试的环境。驱动模块在大多数场合称为“主程序”,它接收测试数据并将这些数据传递到被测试模块,被测试模块被调用后,“主程序”打印“进入-退出”消息。

  驱动模块和桩模块是测试使用的软件,而不是软件产品的组成部分,但它需要一定的开发费用。若驱动和桩模块比较简单,实际开销相对低些。遗憾的是,仅用简单的驱动模块和桩模块不能完成某些模块的测试任务,这些模块的单元测试只能采用下面讨论的综合测试方法。

  提高模块的内聚度可简化单元测试,如果每个模块只能完成一个,所需测试用例数目将显着减少,模块中的错误也更容易发现。

  二、经验总结

  工厂在组装一台电视机之前,会对每个元件都进行测试,这,是单元测试。

  其实我们每天都在做单元测试。你写了一个函数,除了极简单的外,总是要执行一下,看看功能是否正常,有时还要想办法输出些数据,如弹出信息窗口什么的,这,也是单元测试,我们把这种单元测试称为临时单元测试。只进行了临时单元测试的软件,针对代码的测试非常不完整,代码覆盖率要超过70%都非常困难,未覆盖的代码可能遗留大量的细小的错误,这些错误还会互相影响,当BUG暴露出来的时候难于调试,大幅度提高后期测试和维护成本,也降低了研发商的竞争力。能说,进行充分的单元测试,是提高软件质量,降低研发成本的必由之路。

  对于程式员来说,如果养成了对自己写的代码进行单元测试的习惯,不仅能写出高质量的代码,而且还能提高编程水平。

  要进行充分的单元测试,应专门编写测试代码,并和产品代码隔离。我们认为,比较简单的办法是为产品工程建立对应的测试工程,为每个类建立对应的测试类,为每个函数(非常简单的除外)建立测试函数。首先几个概念谈谈我们的看法。

  一般认为,在结构化程式时代,单元测试所说的单元是指函数,在当今的面向对象时代,单元测试所说的单元是指类。以我们的实践来看,以类作为测试单位,复杂度高,可操作性较差,因此仍然主张以函数作为单元测试的测试单位,但能用一个测试类来组织某个类的所有测试函数。单元测试不应过分强调面向对象,因为局部代码依然是结构化的。单元测试的工作量较大,简单实用高效才是硬道理。

  有一种看法是,只测试类的接口(公有函数),不测试其他函数,从面向对象角度来看,确实有其道理,不过,测试的目的是找错并终排错,因此,只要是包含错误的可能性较大的函数都要测试,跟函数是否私有没有关系。对于C++来说,能用一种简单的方法区隔需测试的函数:简单的函数如数据读写函数的实目前头文件中编写(inline函数),所有在源文件编写实现的函数都要进行测试(构造函数和析构函数除外)。

  什么时候测试?单元测试越早越好,早到什么程度?XP研发理论讲究TDD,即测试驱动研发,先编写测试代码,再进行研发。在实际的工作中,能不必过分强调先什么后什么,重要的是高效和感觉舒适。从我们的经验来看,先编写产品函数的框架,然后编写测试函数,针对产品函数的功能编写测试用例,然后编写产品函数的代码,每写一个功能点都运行测试,随时补充测试用例。所谓先编写产品函数的框架,是指先编写函数空的实现,有返回值的随便返回一个值,编译通过后再编写测试代码,这时,函数名、参数表、返回类型都应该确定下来了,所编写的测试代码以后需修改的可能性比较小。

  由谁测试?单元测试和其他测试不同,单元测试可看作是编码工作的一部分,应该由程式员完成,也是说,经过了单元测试的代码才是已完成的代码,提交产品代码时也要同时提交测试代码。测试部门能作一定程度的审核。

  关于桩代码,我们认为,单元测试应避免编写桩代码。桩代码是用来代替某些代码的代码,例如,产品函数或测试函数调用了一个未编写的函数,能编写桩函数来代替该被调用的函数,桩代码也用于实现测试隔离。采用由底向上的方式进行研发,底层的代码先研发并先测试,能避免编写桩代码,这样做的好处有:减少了工作量;测试上层函数时,也是对下层函数的间接测试;当下层函数修改时,通过回归测试能确认修改是否导致上层函数产生错误。