测试驱动开发 ―― 一种真正的工程化开发实践 (转载自孙鸣、邓辉
自从软件危机的概念被提出以来,人们就在不断地探索解决之道。期间,这些探索者们从其他如硬件、建筑等相对成熟的行业借鉴了不少经验和知识,希望能够以工程化的方法解决软件领域所面对的难题,并提出了“软件工程”这样一个知识框架用以指导实践。但是,几十年过去了,结果表明,“软件工程”为我们带来的对软件开发本身反思方面的作用要远远大于解决软件危机方面的作用。 关于软件本身的特点和规律,JackW.Reeves在其著名的论文“WhatIsSoftwareDesign?”中有深刻的论述。在此,仅列出几个重要的结论: 在我们实际的软件开发中,最令人头疼的问题莫过于两点:1、时间有限,要实现的功能太多;2、bug层出不穷,好像永远也改不完。一般来讲,造成这两个问题的根源都是由于违背了上述的软件本身的规律。下面我们来简单分析一下。 我们的需求分析结果是以软件需求规格说明书的形式交付的,描述的语言是自然语言。自然语言往往是含糊地。虽然对人来讲觉得可能已经很清楚了,但是对于真正去执行的计算机来说,精确度远远不够。因此,需求和实现之间存在着许多“不那么明确”的地方。由于软件的设计成本很低,因此,“负责任”开发人员在设计和实现时,会不经意地把这些不明确的地方最大化,造成需求和软件开发成本的隐式膨胀。如果我们要求每增加一个设计元素,那么设计开发人员就要去爬十层楼,相信我们的软件会减掉不少“赘肉”:) 此外,大家想想,我们的软件中的bug都是在什么阶段大量涌现的?没错,是联调阶段。正是由于软件的构建成本很低,因此,我们才得以在前期不那么有纪律地进行编码,然后把软件构建出来进行调试,验证。把软件先构建出来再验证本身没什么问题,问题在于由于软件不受任何物理规律约束,并且非常精确,因此任何一丁点的修改都可能造成难以预料的严重后果。而我们也缺乏一种有效的检查修改所造成影响的手段。测试部门的人工测试或者基于界面的robot测试非常的低效且容易遗漏。 那么我们怎么做才能符合软件本身的规律,从而在最大程度上避免上述问题呢?我们需要用和实现语言同样精确的语言来描述需求;我们需要用和实现语言同样精确的语言来描述验收条件;我们需要足够细粒度的检查点来固定我们的软件;这些检查点的运行要足够快、成本足够低以便于我们可以经常性的运行它们。这意味着什么呢?这意味着开发人员在编写实现代码前,要先用同样的语言编写测试,用测试代码来表达需求和验收条件,用测试来驱动整个的开发过程。这样做能有效地解决上述问题吗?我们来分析一下。 软件是精确地,容不得半点含糊。因此用编程语言描述需求可以避免那些似是而非的情况,如果觉得自己很清楚一个需求,那么请用编程语言写出一个测试用例,精确地表达需求场景和验收条件,如果写不出来,那就表明还没有搞清楚。此外,有了这个可以用编程语言描述的验收条件,就有了准确的判断完成的标准。一切以完成验收条件为目标,这样也就避免了因为没有精确目标而随手编写多余的代码。 另一方面,如果用测试来驱动我们的开发,那么每一个测试用例就充当了用以固定软件行为的检查点的角色。随着功能的不断增加,这些测试用例不断地累积,形成了一张坚固的安全网络。每当我们增加新功能时;每当我们更改bug时;每当我们重构代码时;我们都可以即时地运行这些测试,然后就可以立即得到反馈。有了这些检查点,一旦发现问题,可以很快地进行定位:问题一定出在上一次正常运行和这一次故障运行之间的修改上面,我们的测试用例的粒度越小,运行得越频繁,问题定位起来就越容易。 如果用测试来驱动开发,那么我们写出的代码将天生就具有可测试性。而可测试性是好的设计的重要标志。我们的实现代码将完全可以脱离预先设定的环境进行测试,测试的粒度完全可以根据需要进行调整。和完整的系统测试相比,这样的测试成本更低、运行更快、更灵活,更加可控,它们也是持续集成的重要基石。 软件开发就像是攀岩,既充满乐趣,又深具挑战,有时甚至危险重重。正如攀岩时最安全有效的方法是保证我们的四肢中每次仅移动有一个一样,我们在软件开发中也要遵守这样的纪律。在软件开发活动中,我们的四肢是什么呢?它们分别是:编写测试代码;编写实现代码;修改测试代码;修改实现代码。我们要非常清楚地知道我们正在移动得是四肢中的哪一个,并严格按照纪律执行。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |