Chinaunix首页 | 论坛 | 博客
  • 博客访问: 23792
  • 博文数量: 16
  • 博客积分: 656
  • 博客等级: 上士
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-16 09:55
文章分类

全部博文(16)

文章存档

2009年(5)

2008年(11)

我的朋友
最近访客

分类: Java

2008-10-28 16:40:15

原文链接:http://en.wikipedia.org/wiki/Test-driven_development
Test-driven development
来自 Wikipedia:开放性的百科全书
Test-Driven Development (TDD)是一种软件开发技术。这种技术中,在每个很短的周期中首先编写测试用例(test cases)覆盖新的功能和需改进的功能,然后写必要的实现代码以通过测试用例,最终用重构软件去适应变化。在实际开发前写测试用例的益处是保证能够根据 任何变化得到反馈信息。从业者(practitioners)强调test-driven development是一种软件设计方法,而不仅仅是一种测试方法。
Test-Driven Development 这个概念始于二十世纪晚期,是一个和测试先行编程概念(the test-first programming)相关的概念,但是最近它(译者注:“它”指Test-Driven Development)凭自己的能力得到了广泛的关注。
这个概念也可以结合其它技术用于改进和去除以前用其它方式开发的软件的缺陷。

目录

1.依赖(原文:requirements)

2.Test-Driven Development周期
    2.1 1.添加一个test
    2.2 2.运行所有的test,新的test要失败(原文:Run all tests and see the new one fail)
    2.3 3.写一些代码
    2.4 4.运行自动测试,使所有的test都成功(原文:Run the automated tests and see them succeed)
    2.5 5.代码重构
    2.6 重复以上步骤
3.开发风格
4.优点
5.局限性
6.代码可见
7.伪造、仿造和集成测试(原文:Fakes, mocks and integration tests)
8.参考
9.附加参考
10.一些链接
 
 
1.依赖(原文:requirements)
Test-driven development依赖于自动单元测试(an automated unit test)。自动单元测试(an automated unit test)要在写代码之前先写,其中定义了代码的需求。这些测试中包含了非真即假的断言(assertions)。
运行这些测试可以快速确定代码展开的行为以及重构代码的正确性。基于xUnit概念(请查看单元测试框架列表)的测试框架提供了制作和运行一系列自动测试用例的机制。
2.Test-Driven Development周期
以下周期的顺序参考Test-Driven Development by Example这本书。此书是用现代手法阐述Test-Driven Development这一概念的权威作品。
    2.1 添加一个test
    在test-driven development中,一切新功能的开发从写test开始。由于功能没有被实现,所以这一步中所写的test必然会失败。开发人员为了确保清楚理解各 个规格和新功能中所有的需求,可以通过分析用例(use cases)和user stories全面掌握需求和异常情况。
    这也说明了有可能保留或修改现有的test。这一特性是Test-driven development和完成代码后的单元测试一个微妙却重要的区别,它使你将精力集中在代码前的需求上。
    
    2.2 运行所有的test,新的test要失败(原文:Run all tests and see the new one fail)
    这里保证test工作正常,而且新的test在缺少实现代码的情况下没有失误的通过测试。
    新的test预期应该失败。这里以否定形式测试test本身(This step tests the test itself, in the negative)。从某种程度上讲,“否定测试”(a negative test)和测试人员(testers)类似,当一个特性应该失败时确保它失败,例如错误的数据输入。
    “肯定测试”(positive tests)保证代码按照预期的设定工作,例如正确的数据输入,它(译者注:指“肯定测试”)和“否定测试”(a negative test)配合使用。(保证它工作,然后改变它使它中断并保证它中断)(原文:"Make sure it works, then change one thing to make it break and make sure it breaks.")
    整个一系列单元测试都服务于此需求,通过检查每一个test以保证“否定测试”按照预期的原因失败。
    这一技术避免了test总是通过成功而使test失去价值这一弊病。第一次运行新的test,看着它失败,这是一个至关重要的健全的测试。
    
    2.3 写一些代码
    写一些代码让test成功通过。新写的代码不完美,甚至可能用不优雅的方式通过了测试。应该接受这个情况,因为后面的步骤中会对代码进行改进和打磨。
    
    2.4 运行自动测试,使所有的test都成功(原文:Run the automated tests and see them succeed)
    现在如果所有的测试用例(test cases)都成功的通过,程序员应改相信代码设计到了所有应测得需求。这是到达终点的好的起点。
    
    2.5 代码重构
    现在有必要使代码更清晰。开发人员可以通过重新运行测试用例(test cases)以保证重构没有对任何原有功能造成破坏。去除冗余是任何一个软件设计中的重要方面。(原文:The concept of removing duplication is an important aspect of any software design.)所以,要去除测试代码(test code)和产品代码(production code)中的任何冗余。例如去除冗余的幻数(magic numbers)和字符串(strings),从而使2.3中写的代码通过。(原文:for example magic numbers or strings that were repeated in both, in order to make the test pass in step 3.)
    
    2.6 重复以上步骤
    开始一个新的test并重复循环周期以推进功能的开发。如果开发人员愿意的话,可以调小开发的步伐,或者增大步伐如果他/她很有信心的话。如果适合test的代码不能很快地通过,那么以前的步伐可能过大。    当使用附加的库时,很重要的一点是不要用过小的步伐而导致仅仅测试了库本身(原文:When using external libraries it is important not to make increments that are so small as to be effectively merely testing the library itself)。除非有一些原因是你相信库本身存在bug或者不足以服务于所有的需求(原文:unless there is some reason to believe that the library is buggy or is not sufficiently feature complete to serve all the needs of the main program being written.)。
    
3.开发风格
很多方面都可以使用test-driven development,例如"kiss it simple,stupid"(KISS)和"You Ain't Gonna Need It"(YANGI)。集中精力写必要的代码以使其通过test,设计会越来越清晰,因此常常能用其它方法实现。(一些人还建议使用"Fake it, till you make it"这个原则)。为 了运用先进的设计概念(像Design Pattern),写test时会运用这种模式。(To achieve some advanced design concept (such as a Design Pattern),tests are written that will generate that design.)代码可能会比目标代码要简洁,但是仍然通过所有的test.起初这可能会令人不安,但是却让开发人员能够集中精力在重要的事情上。
   Test-driven development 要求开发人员首先使测试用例(test cases)失败。这确保test确实在工作并能捕捉一个错误。之后,正常的循环周期开始了。"红/绿/重构"已经成为了Test-Driven-Development 格言("Test-Driven Development Mantra"),其中“红”表示失败而“绿”表示通过。
Test-driven development不断地重复着“失败”、“通过”、“重构”的步骤。得到预期的测试结果巩固了编程者头脑中的代码模型、增加了自信、提高生产能力。
   先进的实践使test-driven development发展出了Acceptance Test-driven development[ATDD]。这种技术中,客户制定的标准自动进入acceptance tests,它们驱动传统的
单元测试驱动开发[UTDD]过程(the traditional unit test-driven development UTDD]process.) 这个过程保证客户用自动机制决定软件是否迎合了需求。用ATDD这种技术,现在开发团队有了一个明确的目标,那就是acceptance tests,它使开发团队始终致力于从user story得来的客户的真正的需求。

4.优点
   最近的研究表明使用TDD意味着写更多的测试,而且编程者写更多的测试意在提高生产力。关于代码质量的猜侧以及TDD和生产力之间的直接联系是不能确定的。(原文:Hypotheses relating to code quality and a more direct correlation between TDD and productivity were inconclusive.)
   完全使用TDD开发一个新工程的编程者说他们几乎不需要测试人员。(原文:Programmers using pure TDD on new ("greenfield") projects report they only rarely feel the need to invoke a debugger. )
   结合版本控制系统(a Version control system),当测试没有通过时,可以恢复为上一个通过测试的代码版本,这可能比调试的生产率要更高。
   Test-driven development 帮助软件开发的更好、更快。它提供的不仅仅是对于对错的简单验证,更驱动着如何设计程序。当精力首先集中在测试用例时,你必须首先想象客户如何使用这些功能。所以,编程者只关心接口而不是实现类。这一优点是对Design by Contract的补充,因为通过测试用例去实现代码而不是通过数学断言或预想。
   test-driven development有能力在必要时使用小步伐进行开发。它允许编程者对手头的工作集中精力,因为首要的目标是使测试通过。异常情况的用例和错误的捕获不是在最开始进行的。对于创造额外环境的测试用例属于单独的应用(原文:Tests to create these extraneous circumstances are implemented separately.)。另一个优点是:当使用得当,test-driven development 保证所有的代码都被测试用例覆盖。这可以使编程者以及再次开发者很大程度上信任代码。
   这是真的,单元测试使更多的代码需要TDD,因为它使整体实现时间缩短。大量的测试限制了代码的缺陷。早期和频繁的测试帮助我们在开发周期的早期发现缺陷,并阻止这些缺陷成为根深蒂固或代价昂贵的问题(原文:The early and frequent nature of the tests helps to catch defects early in the development cycle, preventing them from becoming endemic and expensive problems.)。早期消除缺陷经常能避免以后单调乏味的调试(原文:Eliminating defects early in the process usually avoids lengthy and tedious debugging later in the project.)。
    TDD带来的是模块化、更灵活、可扩展的代码。因为方法论要求开发人员要求依据小单元来考虑软件,这些小单元可以独立生成和进行测试,而且以后进行集成到一起。这带来的是更小、更集中的类,更小的耦合,更干净的接口。“Mock Object design pattern”也致力于代码的整体模块化,这个模式的要求是:所写的代码可以使模块从用于单元测试的mock版本到用于开发的“真正的”版本方便的切换。
   
5.局限性
   TDD在某些情况下很难适用。例如图形用户接口、数据库相关的系统,因为这些系统包含了复杂的输入、输出,没有可以进行单元测试和重构的孤立的单元(原文:where systems with complex input and output were not designed for isolated unit testing or refactoring.)。
 
6.代码可见
      存在三种测试代码:白盒测试、黑盒测试、玻璃盒测试。黑盒测试测试的是接口的边界值。因为能保证软件的模块性并强行侧重于模块接口,所以几乎所有的单元测试都由黑盒测试组成。当测试可以观察并改变属于软件的状态时,我们用白盒测试(White box testing occurs when your tests can both observe and mutate state belonging to the software under test. )。这些测试方式被强烈抵制,因为测试到的一些微小的bug很可能由测试用例本身存在的bug导致。玻璃盒测试用于仅仅观察但不改变产品软件的状态。玻璃盒测试包括验证一个方法在硬件层次的输出。例如,验证跳跃表(a skip-list)的链接的设置是否合适,对于跳跃表的成功和领错误实现是至关重要。测试包中的代码能够清晰的访问所测试的代码。几乎所有可以想象的用例中,这样的访问涉及到了公开接口、程序和调用的方法。“mock”对象的使用保证了不触及“隐藏”信息,保证了测试的独立性(原文:The use of "mock objects" ensures information hiding remains intact, guaranteeing a total separation of concerns.)。
      用于TDD的单元测试代码几乎从来不会放在同一个工程或要测的模块中(原文:Unit test code for TDD is almost never written within the same project or
      module as the code being tested.)。测试代码会放到一个独立的模块或库中,这样产品代码可以保持原样。把TDD代码放到同一个模块(译者注:指要测试的模块)中会从根本上改变产品代码。分情况编译会带来微小的bug产生。(译者认为这句话的意思是:如果将测试代码和产品代码放在一起,然后分情况编译以区别它们仍然会带来小的bug)
    有人会说,严格的黑盒测试是不会访问私有的数据和方法的。这是有意的(原文:This is intentional);随着软件的一步步发展,你会发现一个类的实现从根本上改变了。
    记住,test-driven development中决定性的一步是重构。重构会引入变化:对私有方法的添加或删除,或是改变现有方法的类型。这些变化是不应该破坏现有的测试的。
    使用玻璃盒测试的单元测试代码和产品代码具有高耦合性;改变一个类或模块的实现意味着也必须更新或丢弃现有的代码,而这是永远都不应该发生的事情。因为这个原因,使用玻璃盒测试的几率应降到最低,而白盒测试在test-driven development 中则永远不要使用。
   无论如何,部署问题应该有其思想(原文:In all cases, thought must be given to the question of deployment.)。最好的方法是开发你的软件,那么你就有三个主要的部件。第一个主要的部件是应用框架自身的单元测试器。第二个产品逻辑的主要入口模块。这些模块将链接(最好是动态链接)到一至多个库上,每个库实现了一些或所有的业务逻辑。这能保证模块整体和彻底的可部署性(原文:This guarantees total modularity and is thoroughly deployable.)。
      
7.伪造、仿造和集成测试(原文:Fakes, mocks and integration tests)
    单元测试得以其名是因为它们测试的是代码的一个单元,而不管你的代码中有上百个单元测试或只有5个。在一个程序中,一个测试包是永远都不应该跨越模块的。这种做法的风险是引入了大范围的延迟,而更糟糕的或许是,它无意间将你的单元测试变成了集成测试。后者尤为严重,因为在相互关联的模块组成的链中,如果任何模块失败了,你的测试就会失败,并且没有任何信息表明在哪里、为什么失败。这击毁了单元测试的目的。
   当开发中的代码依赖于数据库或web服务,或者其它的外部程序和服务时,好像就会出现一个问题。然而,这不是一个问题,而是一个设计更多模块的可能性和驱动力,这些模块中有更具可测试性,更具可重用性的代码。需要下面两个步骤:
   (1)当最终的设计中需要外部的访问时,需要定义接口去规定合理的访问。
   (2)实现接口有两种方式,一种是实际地去访问外部程序,另一种是伪造或仿造对象(原文:and the other is a fake or mock object)。伪造对象(fake object)需要稍多的设置,不仅仅向追踪日志(原文:a trace-log)或控制台增加一句“保存Person对象”。伪造对象(fake object) 也被称为存根对象(原文:stub objects)。仿造对象(mock object)的不同在于它包含可以使自身不能通过测试的断言(assertions),例如包含了不合法的用户名和其它数据。仿造对象和伪造对象方法常常返回测试程序所依赖相同的、现实的数据,而这些数据看起来就像来自数据库或用户一样。
   这个方法的缺点是,在TDD进程中,实际的数据库或其它访问代码永远都无法被测到。我们必须避免一个疏忽:实例化前面提到接口(用于测试驱动的代码)时,需要其它的测试。(原文:other tests are needed that instantiate the test-driven code with its 'real' implementations of the interfaces discussed above. )。多数开发者发现把这些测试同TDD单元测试分开,然后再进行集成测试时参考它们是很有用的事情。这些测试会存在的越来越少,较单元测试来讲运行地也少。不过,仍然可以用相同的测试框架,例如 xUnit去实现。
   集成测试会改变持久化存储或数据库,所以应该慎用,使其在任何测试失败的情况下都可以保持可重复使用。要做到这一点,可以结合下面的相关技术:
      1。将TearDown方法集成到测试框架中。
      2。用try..catch...finally块进行合理的异常处理
      3。当自动事务中包含了写、读、删除操作时,使用数据库事务。
      jMock等现有框架使生成和使用伪造对象(mock objects)更容易。
      
8.参考
   1.  a b Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft .NET, Microsoft Press, 2004.
   2.  Feathers, M. Working Effectively with Legacy Code, Prentice Hall, 2004
   3.  a b Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
   4.  Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of Test-first Approach to Programming. Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005. (NRC 47445). Retrieved on 2008-01-14. “We found that test-first students on average wrote more tests and, in turn, students who wrote more tests tended to be more productive.”
   5.  Proffitt, Jacob. TDD Proven Effective! Or is it?. Retrieved on 2008-02-21. “So TDD's relationship to quality is problematic at best. Its relationship to productivity is more interesting. I hope there's a follow-up study because the productivity numbers simply don't add up very well to me. There is an undeniable correlation between productivity and the number of tests, but that correlation is actually stronger in the non-TDD group (which had a single outlier compared to roughly half of the TDD group being outside the 95% band).”
   6.  Clark, Mike. Test-Driven Development with JUnit Workshop. Clarkware Consulting, Inc.. Retrieved on 2007-11-01. “In fact, test-driven development actually helps you meet your deadlines by eliminating debugging time, minimizing design speculation and re-work, and reducing the cost and fear of changing working code.”
   7.  Llopis, Noel (20 February 2005). Stepping Through the Looking Glass: Test-Driven Game Development (Part 1). Games from Within. Retrieved on 2007-11-01. “Comparing [TDD] to the non-test-driven development approach, you're replacing all the mental checking and debugger stepping with code that verifies that your program does exactly what you intended it to do.”
   8.  Muller, Matthias M.; Padberg, Frank. About the Return on Investment of Test-Driven Development (PDF) 6. Universitat Karlsruhe, Germany. Retrieved on 2007-11-01.

9.附加参考
   1. ^ a b Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft .NET, Microsoft Press, 2004.
   2. ^ Feathers, M. Working Effectively with Legacy Code, Prentice Hall, 2004
   3. ^ a b Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
   4. ^ Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of Test-first Approach to Programming. Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005. (NRC 47445). Retrieved on 2008-01-14. “We found that test-first students on average wrote more tests and, in turn, students who wrote more tests tended to be more productive.”
   5. ^ Proffitt, Jacob. TDD Proven Effective! Or is it?. Retrieved on 2008-02-21. “So TDD's relationship to quality is problematic at best. Its relationship to productivity is more interesting. I hope there's a follow-up study because the productivity numbers simply don't add up very well to me. There is an undeniable correlation between productivity and the number of tests, but that correlation is actually stronger in the non-TDD group (which had a single outlier compared to roughly half of the TDD group being outside the 95% band).”
   6. ^ Clark, Mike. Test-Driven Development with JUnit Workshop. Clarkware Consulting, Inc.. Retrieved on 2007-11-01. “In fact, test-driven development actually helps you meet your deadlines by eliminating debugging time, minimizing design speculation and re-work, and reducing the cost and fear of changing working code.”
   7. ^ Llopis, Noel (20 February 2005). Stepping Through the Looking Glass: Test-Driven Game Development (Part 1). Games from Within. Retrieved on 2007-11-01. “Comparing [TDD] to the non-test-driven development approach, you're replacing all the mental checking and debugger stepping with code that verifies that your program does exactly what you intended it to do.”
   8. ^ Muller, Matthias M.; Padberg, Frank. About the Return on Investment of Test-Driven Development (PDF) 6. Universitat Karlsruhe, Germany. Retrieved on 2007-11-01.

10.一些链接
    * Concordion acceptance testing framework for Java
    * Typemock is a powerful and controversial mocking framework for .NET
    * The Various Meanings of TDD
    * Three Rules of TDD
    * Extreme perl - Unit testing
    * Write Maintainable Unit Tests That Will Save You Time And Tears
    * Improving Application Quality Using Test-Driven Development by Craig Murphy. This article provides an introduction to Test-Driven Development with concrete examples using NUnit
    * testdriven.com on-line test-driven development community
    * Acceptance Test Driven Development
    * Test-driven Development using NUnit tutorial (also Java version available)
    * c2.com Test-driven development from WikiWikiWeb
    * Brief explanation of the Qualities of an Ideal Test
    * team test development A non-programmer driven approach towards test driven development.
    * Test Driven Development with Visual Studio 2005 Team System - Doug Seven, 3/10/2006
    * TDD Anti-Patterns Common mistakes and mishaps when starting out with TDD... a catalog of how to NOT do TDD.
    * Introduction to Test-Driven Design (TDD)
    * XP Episode By Bob Martin and Bob Koss
    * jMock
    * Mocking the Embedded World is an article about adapting the test driven development approach to the embedded software development world with tools suggestions and a case study.
    * Test Driven Development lessons learned
    * The Basics of Test Driven Database Design - Max Guernsey, III, 1/26/2008
    * Test Driven Development in .NET example for TDD in Visual Studio and .NET including WatiN test framework for web applications

原文链接:http://en.wikipedia.org/wiki/Test-driven_development
阅读(841) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~