在软件开发的过程中,编写单元测试通常被认为是首要任务,但往往在时间紧迫时被忽略。作为团队领导或管理者,都知道测试是必要的,但当临近截止日期时,往往会减少对测试的重视,而更多地关注编写代码。因此,在测试领域似乎存在某种紧张关系。都知道测试对有好处,但一旦项目面临压力,似乎就不再进行测试了。
埃兹格·迪杰斯特拉(Edsger W. Dijkstra)曾说过:“程序测试可以用来显示错误的存在,但永远不能证明它们的不存在!”这意味着测试不能100%保证软件没有错误。但它确实有很大帮助。可以反过来说,如果不进行测试,几乎可以100%保证会有错误,除非正在编写一个“Hello World!”程序的版本。即使是这个程序,也会进行测试,因为一旦输入了代码,会好奇输出是否真的是“Hello World!”。
这就引出了所有人都会做的第一种测试形式:手动测试。编写了程序,然后启动它以验证结果。对于一个简单的“Hello World”,这可能足够了,但一旦涉及到更复杂的内容,这将导致浪费时间。这也是一些重复性的工作,有一组已知的操作和结果。
这难道不是发明计算机的初衷吗?对于“Hello World”,这不是一个大问题,但当创建一个Web应用程序时,想要测试只有在经过10个页面、点击一些按钮并输入大量(正确)数据字段之后才会出现的某些条件,可以看到自动化这个过程将节省大量时间。如果能让测试运行器直接执行想要测试的函数,而不是花费半分钟到达那个函数,将获得巨大的节省!
但这意味着需要编写更多的代码。编写更多的代码需要更多的时间和努力。所以它将需要更多的时间,项目将完成得更慢。
或者也许不是这样。让创建一个控制台应用程序来计算两个整数的最大公约数(GCD)。有很多方法可以解决这个问题,但为了简单起见,将:
1. 输入两个整数
2. 使用喜欢的任何算法计算GCD
3. 显示输出
让经历正常的开发周期。通常会编写一个main()函数,它获取两个整数,调用一个函数来计算GCD,然后显示结果。
测试。在控制台中输入两个整数将花费一些时间,如果需要多次重复这个过程来使代码正确,这将变得相当无聊。在控制台应用程序中输入错误的东西也很容易,导致程序崩溃。这意味着必须重新启动程序,再次输入两个数字,然后再次验证结果。请注意,谈论的是一个只接受两个输入值的控制台应用程序,不需要点击(如Web应用程序),已经看到这将花费一些时间。
然后可能想要测试更多的值,这意味着重新启动程序,输入两个数字(正确),测试……所以立即看到这将不会被执行,因为这需要太多时间。边缘情况将被遗忘,错误只会在生产中被发现!
此外,当更改某些内容时,需要再次运行所有测试(手动),有很高的风险被遗忘,或者采取捷径。
测试工作将没有痕迹。除非在测试期间手动将这项工作添加到待办事项列表中,否则不会写入日志文件。
负面反馈循环。通常,当项目因某种原因被推迟时,它们会进入负面反馈循环。或者有时,一开始就决定跳过编写测试。这将带到以下图表:
项目被推迟,所以必须生产更多(代码)。所以,不再“浪费时间”进行测试,而是开发,开发,开发。结果,代码质量将降低,这将(迟早)导致返工。这种返工通常会在最糟糕的时候变得紧急(有人说墨菲是个乐观主义者!)。由于返工,其他事情无法完成,所以项目现在将更加推迟。
所以奇怪的是,编码越多,完成项目的时间就越晚。作为反应,通常会有更多的开发人员被分配到项目上,这只会增加负面循环。
缺乏测试将不可避免地意味着客户会在验收和生产环境中发现更多的错误。所以客户的信任会迅速下降,这将导致负面反馈。这种反馈会传达到(已经过度劳累的)开发人员,他们将进入“开发者疲劳”。这会导致动力下降,开发人员离开……所以项目将更加推迟。
打破负面循环。认为已经明白了有一种方法可以解决这个问题。让画一个不同的图表:
可以从“项目按时”的泡沫开始。开发代码,并立即测试它。测试最好是自动化的(编码的),这样它们可以轻松高效地执行。在开发和测试之间有紧密的集成,所以这个循环可以快速执行。当循环完成时,可以确定代码质量足够高;因为它通过了测试。此外,客户发现的错误更少,这将确保客户保持信任。如果他们确实发现了一个错误(这仍然是可能的),那么可以调整测试集,以避免重复错误。
由于这个原因,不需要返工,项目可以继续进行。
当项目已经推迟时,切换到这种方法将需要一些时间。可能需要冻结特性。不要编写新代码,而是开始为最(烦人 - 可见 - 昂贵)的错误部分编写测试。
在这种情况下,开始为整个代码库编写测试是没有意义的。它的某些部分将是好的,所以不要浪费时间。但是要为其他部分编写测试。当在这个阶段进入一个项目时,尝试找到最严重的问题(优先排序),然后在那里编写一些测试。然后,更容易“快速”地纠正代码,并在处理其他区域时保持正确。因为自动化测试经常运行,重复错误的风险降低了。所以,可以开始有效地稳定项目。
通常,这也需要对代码进行一些重构,使其可测试。将在另一篇文章中讨论这个问题。
结论。在大多数项目中,将在编写测试和编写代码之间寻求平衡。但希望已经很清楚,测试是项目的一个很好的加速器,而不是浪费时间。