因为错误是不可避免的,所以需要讨论一下如何尽可能地把缺陷排除在软件开发周期之外,以便尽量减少错误并提高软件质量。事实上,这主要有两大类技术,分别是缺陷预防和缺陷检测。
缺陷预防
缺陷预防技术一般是从开发人员角度来说的,包括编写更好的设计规范,实施代码审核制度(code review),运行代码静态分析工具(static analysis tool),运行单元测试(unit testing)(往往是自动化单元测试)。所有的这些缺陷预防技术都有些根本的问题,如果不解决这些根本问题,这些技术都不会很有效。下面让我们来一一讲述这些问题。
问题1:“开发人员只能是个糟糕的测试者”
让开发人员寻找自己程序代码中的缺陷,这种方法的有效性很值得怀疑。如果他们善于发现缺陷,难道他们不应该在编写这些代码的时候避免引入这些缺陷吗?因为开发人员是从编写程序的角度出发,所以他们必然会有盲点。这是为什么很多关注软件质量的企业都会聘用不同的人来测试程序。这并不奇怪,其实是要求测试人员从不同于开发人员的视角来测试程序,这样的测试过程不会带有开发人员的固有成见。而且测试人员拥有的那种“如何才能攻破这个功能”的态度和开发人员那种“如何才能实现这个功能”的态度是相辅相成、缺一不可的。
这不是说开发人员不需要做任何测试。测试驱动开发(test-driven development,简称TDD),顾名思义,它是一个开发任务,我个人也坚定不移地相信单元测试应该由开发该段代码的程序员编写。有很多情况,比如像格式化(formatting)、数据验证(data-validity)和异常条件(exception condition)等,都需要在开发过程中被及时发现处理。前面已经说过,即使这样,我们还需要第二双眼睛来检查一些更微妙的情况,这样可以保证在用户使用软件之前发现这些缺陷。
问题2:“处于静止状态的软件”
类似代码审核或静态分析的技术不要求实际运行软件,也是说它们分析的是处于静止状态的软件。一般来说,这包括分析程序源代码(source code)、目标代码(object code)和终编译生成的二进制文件或程序集(assembly)的内容。遗憾的是,如果程序不在真实运行环境中运行起来,很多缺陷不会被触发。第1章中讨论的大多数缺陷都属于这一类:除非在运行软件时使用真实的输入数据,否则无济于事,这些缺陷仍然隐藏得很深。
问题3:“缺乏数据”
软件需要接收输入和数据,才能覆盖程序中的各个代码路径(path)。具体执行的是哪些代码路径由程序获得的具体输入、当前软件的内部状态(内部各个数据结构和变量的值)、外部因素比(如数据库和数据文件)来共同决定。往往会出现这样的情况,软件运行一段时间后,当数据量积累到一定程度,软件出现故障了。这是因为开发时的测试一般要求在短时间内必须完成,所以开发时往往不能覆盖这样的情况。
未来也许会出现一些工具或技术,开发人员凭借它们可以写出无缺陷的代码 。当然,这里说的更多是狭义上的缺陷,例如,使用检测缓冲区溢出 (buffer overflow)技术可以很大程度上消除这方面的软件缺陷,现在基本上也已经做到这一点了。如果这种趋势可以长期广泛地保持下去,软件测试所需要的工作量会相应减少很多。但我个人觉得,真正实现这一点有很长的路要走,可能还要花上几十年的时间。在这之前,我们仍然需要实现如下的一些措施,在测试中使用不同于程序员视角的“第二双眼睛”,在模拟的真实运行环境中运行软件以及使用大量接近真实数据的测试数据。
谁能提供前面所说的“第二双眼睛”呢?答案是软件测试人员。他们可以熟练使用各种测试技术来检测软件缺陷,并将其上报,这样,缺陷才能被修复。测试是一个动态的过程,它包括在不同的环境中运行软件,使用合理的测试数据,并在较短的测试周期内尽可能多地尝试不同的输入值。这是软件测试人员可以施展身手的地方。