随着全球经济的发展与计算机技术的普及,各行业对计算机软件的需要量日益增加。与此同时对软件的质量要求也越来越高。而与之形成鲜明对比的是,随着软件需要的增加和规模的增大,能做出及时交付给用户以及让用户满意的软件却变得难上加难。传统的软件工程方法已经遭到人们的质疑,很多改进的软件开发方法便应运而生。极限编程(eXtreme Programming, XP)便是在这样一种环境下出现的新型的适用于中小型系统的敏捷开发方法。而极限编程中很具有特色的原则就是采用测试驱动型的开发模式。测试驱动开发是极限编程方法中软件开发具体实践的体现,在保证软件代码的质量上起到了至关重要的作用。同时,它也正成为一种新的思潮在业界推广开来。
业界软件开发的过程一直在被传统的软件工程方法主导着。传统的软件工程方法按照瀑布模型或其变型从系统的问题定义、可行性分析、需求定义等一路下来,每一步的开始都要以上一步的完成作为前提,例如对系统的需求分析就要求完全分析结束后再进到下一阶段。如果其中一步没有完成,或者虽然完成,但是存在问题,那对以后的开发过程会产生不可估量的影响。在业界对软件质量越来越关注的情况下,一些新的软件开发思想如雨后春笋般的涌现了出来,极限编程就是其中的一种影响很大的新思想。
极限编程是1998年由Smalltalk社群中的大师级人物Kent Beck首先倡导的一种新型软件开发方法,它是一个周密而严谨的软件开发流程。它基于简单、交流、反馈、勇气的原则,在充分考虑到人的因素的前提下进行,达到客户的最大满意度。这种方法适用于中、小型系统的开发。这种轻量级的软件开发方法在软件质量上提出了极高的要求。为了保证开发出的软件的质量,该方法提出测试驱动开发(TDD)的思想。
测试驱动开发有别于以往的先编码后测试的开发过程,Kent Beck提出的该开发方法是反其道而行之。在打算添加某项新功能时,先不要急着写程序代码,而是为未来要编写的代码先写一段测试用例。此时利用自动化的测试工具来对测试用例进行执行,当然结果就是通不过。为了要使得该测试用例能够正确的执行,我们就要对进行代码的编写、修改,直到代码符合测试用例的要求,测试用例能够百分之百地正确运行,此时说明该项刚添加的功能通过了单元测试,至少在单元代码一级上已经确实没有问题了。测试驱动开发在自动化测试的工具选择上,推荐使用xUnit系列工具。Kent Beck和Erich Gamma共同开发的开源工具JUnit是Java开发人员进行测试驱动开发的福音。该测试框架在测试驱动开发思想指导下,配合使用该工具,可以极大的提高开发效率,增强软件的质量,最大程度的降低开发成本。
简而言之,测试驱动开发的方法是一种测试在先,编码在后的开发方法。看起来仅是步骤的调整,但其带来的作用却影响深远。测试驱动开发作为极限编程中解决方案的一项基本策略,对极限编程各个原则及策略也有着很深的影响。
它从根本上改变了开发人员在软件开发过程中的开发过程,一改过去编码过后的测试阶段,开发人员对自己编写代码做测试而产生的各种弊端。
极限编程作为一种新式的软件过程方法论,它强调的是人与人合作进行的过程,因此成功的软件开发过程应该充分利用人的优势,而弱化人的缺点,突出了人在软件开发过程中的作用。它同时又是一种高度动态的过程,它通过非常短的迭代周期来应对需求的变化,在编码、测试、聆听、反馈四个基本活动的作用下,在实践的运用过程中,实现极限编程自身的核心价值:
极限编程思想有其自身的核心价值,它们是:交流、简单、反馈、勇气。测试驱动开发作为极限编程中的基本开发原则,也充分体现了这种新型开发思想的价值。
(1)交流在软件开发过程中的作用是毋庸置疑的,交流可以最大程度的减少开发人员、客户、管理人员之间由于沟通不畅造成的误解。极限编程的很多实践都是必须依靠交流来实现的,缺少交流是不能够进行下去的,比如单元测试、结对编程、工作的评估等。测试驱动开发与这些方法密不可分,只有进行结对编程等方法进行的测试驱动开发才是有意义的。这种情况下,同样需要大量的交流,可见交流原则的重要性。
(2)简单这一价值在极限编程的思想中有着很重要的体现,整个极限编程的过程中都体现着简单二字,设计简单、代码简单,只要能简单行事,决不复杂办理。只要符合现在的要求,可以工作,那么简单解决就是最佳的方法。与其实现一个复杂的系统,不如设计一个简单的能满足当前需要的系统,因为你永远考虑不到下一个需求是什么。测试驱动开发正是如此。测试用例的编写本着简单的原则,在符合设计的要求下进行编写,越简单越好。只需要注重眼前的需求,不要考虑以后的需要变化。现阶段的设计满足现阶段的需求即可,显然现阶段的测试也只需满足现阶段的需要即可。测试用例的编写是根据设计而定的,而且可以说,测试用例的编写也是设计的一部分,简单的原则同样在起着指导作用。所以代码的编写亦是根据此原则,算法实现越简单越好,百分之百通过测试即可。
(3)反馈是一项宝贵的资源。在极限编程中,无论是设计、测试、开发过程中,反馈都是非常重要的信息。例如在设计时,尽快获得用户的反馈,并且越详细越好,使得开发人员能够保证自己的成果符合用户的需要。测试亦是如此。测试驱动开发便是贯彻了这一价值。先进行测试用例的编写,利用没有通过测试的错误信息反馈,了解到代码没有通过测试用例的原因,根据该信息了解到出错的地方,再根据出现的问题有针对性的逐步地修改代码,让其渐渐符合测试用例的要求,在运行数次测试用例后,最终让其反馈回百分之百通过的成功信息。
(4)勇气,这是最重要的核心价值。因为XP强调要"拥抱变化",因此对于用户的反馈,要勇于对自己的代码进行修改,丢掉坏的代码。该条价值反映了开发人员应有的心态,而测试驱动开发正是进一步鼓励开发人员,而且在实践方便提供了很好的机制。先写测试后写代码的过程正是这一机制的体现。面对测试用例运行时报出的错误反馈要勇于面对。例如在xUnit测试框架的使用中就要于面对测试时出现的Red Bar,错误信息并不可怕,这正是测试驱动开发的意义所在。针对错误信息来编写及修改代码,勇于面对,最终解决问题顺利通过测试,显示出所期望的Green Bar。勇气又可以进一步的增强信心,提高效率,使得整个过程良性循环发展。
极限编程中提出的设计思想与传统软件工程的大相径庭,它摒弃了传统方法中对设计近乎苛求的原则,弱化了全面细致的设计。在极限编程中,不要求对需求做出非常详细的设计,而是遵循简单的原则,对现有的需求做出简单的设计。不需要为以后考虑,因为你永远不知道将来会增加哪些需求。Martin Fowler提出所谓的设计是要能够让你可以长期很简单地修改软件。
极限编程看似对设计的简化,削弱了开发的依据。但其实它的思想却是进一步明确了软件开发的时候应该更注重眼前的问题,全力去考虑当前的需求,满足客户当前的需要,而不要为以后的需要费时费力,只有这样,才能使做出的软件符合客户的需求。测试驱动开发在实现设计方面有着很大的优势。测试驱动开发的特点之一就是先写测试再写代码。而此时,测试用例编写的意义就非同一般了。一方面,测试用例有着测试代码的通用作用,开发人员在代码编写完成后对其正确性进行判断。另一方面,在极限编程中,设计是一个持续的过程, 测试用例在一定程度是也是需求文档的一种体现。对测试用例的编写其实也就是一个对需求进行分析设计的过程。这一点是极限编程和测试驱动开发独特的一点。测试用例的编写其实就是针对单元的输入输出的判断,对输入输出的设计就是对系统需求分析的过程,不能简单的随便设计,而是最好利用真实的系统数据进行设定。测试用例的编写完成后,代码才开始编写,这里的一切目的只为通过测试,而意义却是为了百分之百地满足系统的需求。测试的编写不再是一件令开发人员痛苦的事情,而是一件为了解系统需求而进行的设计过程,这种转变可以说对软件开发有着极大的积极的影响,这也是测试驱动开发的精髓所在。
将设计融入开发,在开发中完善设计,两者相辅相成的关系在极限编程中体现的充分彻底。也就是这个原因,才使得测试驱动开发这一新思想迅速推广开来。
极限编程的思想是以人为本的思想,它不同于CMM等重量级的开发方法,完全是从工程的角度来进行系统的开发,人在其中完全成为了条条框框下的忠实执行者。极限编程从人性方面考虑的更多,比如每周四十小时工作时,结对编程等。测试驱动开发也体现出了这一原则。
人类的活动具有高度的目的性,建立适当的目标具有重要的心理作用。例如在测试过程中,体现出的现象更是如此。如果我们的主要目的是为了证明程序里面没有错误,那潜意识里就会不自觉地朝这个方向去做,所以在编写测试的过程中,我们就会选择一些尽量使程序不出错的测试数据;但是,如果我们的目标是要证明程序中有错,那就会选择一些易于发现程序所含错误的测试数据。而后一种态度会比前者给程序增添更多的价值。传统测试的定义意味着程序测试的过程是具有破坏性的,其程度甚至达到了不可容忍的地步。
测试驱动开发一改以往的那种破坏性的思想,从人性的角度出发,测试在先,编码在后。而不是像传统的编码完成后再进行破坏性的测试。这样一来,我们的编码就有很明确的目的,每一条代码的目的就是为了能通过测试。从以前的破坏性的方法转移到一种建设性的方法中来。如何来满足这些测试,有了明确的目标,开发人员可以以一种正常人的心态去解决眼前出面的问题,编写高质量的代码去通过这些测试。在这种积极心态的影响下,开发人员的工作效率会有很大的提高,与此同时,这种建设性的方法对整个团队的开发也起着很重要的作用。