搜索
高级检索
高级搜索
书       名 :
著       者 :
出  版  社 :
I  S  B  N:
文献来源:
出版时间 :
测试驱动开发:实战与模式解析:By example
0.00    
图书来源: 浙江图书馆(由图书馆配书)
  • 配送范围:
    全国(除港澳台地区)
  • ISBN:
    9787111423867
  • 作      者:
    (美)Kent Beck著
  • 出 版 社 :
    机械工业出版社
  • 出版日期:
    2013
收藏
编辑推荐
  

  软件工程领域泰斗、极限编程之父Kent Beck力作,荣获第14届Jolt大奖,畅销不衰
  不仅以案例的形式生动地呈现了测试驱动开发的原则和方法,而且详尽地阐述了测试驱动开发的模式和实践
  

    

海报:

  

展开
作者简介
  肯特·贝克(Kent Beck),软件工程领域泰斗、测试驱动开发理念提出者、极限编程之父,在设计模式、测试驱动开发和极限编程领域有很深的造诣,被誉为“计算机软件行业最具创造性才能的领导者之一”和“Java领域最具影响力的10位技术领袖之一”。他为软件行业的发展做出了卓越的贡献。早在1993年,他就与UML之父携手倡导软件开发的模式定义,推动了软件开发模式在软件行业的发展;更突出的贡献是,他提出并推动的极限编程方法学,以及他与Erich Gamma共同打造的JUnit工具,引发了敏捷开发的热潮。他著述颇丰,撰写了《解析极限编程:拥抱变化》、《实现模式》等多本经久不衰的经典著作,这些著作被翻译为多种文字,在世界范围内广泛传播和流行。

  译者简介:
  白云鹏,资深软件开发工程师,对软件过程有深刻理解,曾在微软(美国)总部参与多个项目的全程发布。研究方向是:软件过程改进、测试新技术应用和软件算法分析与设计。出版有《软件测试人员(Java·高级)》等著作。

展开
内容介绍
  《测试驱动开发:实战与模式解析》是测试驱动开发领域的开山之作,由软件工程领域泰斗、极限编程之父Kent Beck撰写,荣获第14界Jolt大奖,10余年畅销不衰,具有里程碑意义。书中不仅以案例的形式呈现了测试驱动开发的原则和方法,而且详尽地阐述了测试驱动开发(TDD)的模式和最佳实践。
  《测试驱动开发:实战与模式解析》共32章,分为三大部分。第一部分(第1~17章)从简单问题入手,介绍了TDD的概念、优势与设计方法,再逐步深入到解决复杂问题的方式;细致讲解了如何在编写程序代码前编写自动化测试,如何先塑造一个设计再通过重构逐渐添加设计上的构思,如何为更复杂的逻辑创建测试等。第二部分(第18~24章)讲解用xUnit创建测试的实例,介绍如何利用xUnit框架创建自己的测试用例,便于高效地进行测试。第三部分(第25~32章)介绍TDD的设计模式,包括部分经典的设计模式以及如何将这些模式与TDD相结合,还介绍了重构的方法,以及TDD中的特殊问题等。本书从始至终贯穿了两个TDD项目,展示了如何轻而易举且卓有成效地编写优质代码的技术。
展开
精彩书摘
  第1章
  Chapter 1
  多币种货币实例
  我们以在WyCash系统中Ward创建的多币种对象作为引子,假设有如下一张报表:
  要制作一张多币种报表,我们需要添加货币名称:
  当然,对应汇率也需要指明:
  $5 + 10 CHF = $10 if rate is 2:1
  $5 * 2 = $10
  为了生成改进的报表,需要怎样做呢?换句话说,什么样的测试集,当其中的测试全部通过时,可以表示已有的程序代码令我们有信心说它正确地生成了报表呢?
  我们能够添加两种不同币种的金额,并且以给定的比率可以相互转换结果。
  我们能够用金额(每股价格)乘以一个数字(股票数目)得到总金额。
  我们还将列出待办事项提醒我们都需要做哪些事情,用以保持精神集中,并且告诉我们何时应该完工。在开始进行第一项的时候,会将它标黑。当完成的时候将它划掉。当我们考虑写出另一个测试的时候,将测试添加到测试列表中。
  就像你从列表中看到的那样,首先可以从乘法算式着手。那么,最先需要的是什么样的对象呢?这可真是个难题。我们还是不从对象而从测试入手吧(我一直这样提醒自己,所以我假设你也和我一样地不开窍吧)。
  让我们再试一次。首先需要的是什么样的测试呢?请看列表,首个测试看起来比较复杂。要么从小处着手,要么是一筹莫展。不就是乘法吗,能难到哪里去呢?我们首先就从乘法开始。
  在写测试代码的时候,我们会想象出利于操作而近乎完美的接口。并且自说自话地描述从外部看操作是什么样的情况。可是我们设想的场景并不是总能成为现实,因而最好以合适的API作为开始,然后事后再加工,而不要一开始就把事情弄得复杂、难看,以及“真实”。
  下面是一个乘法运算的示例:
  public void testMultiplication() {
  Dollar five = new Dollar(5);
  five.times(2);
  assertEquals(10, five.amount);
  }
  (我懂的,我懂的。这里面涉及public字段,副效应,用整数来表示货币金额等问题。这才刚开始嘛。我们会将这些缺点记录下来,然后继续前进,我们会得到一个结果为失败的测试,然后尽可能快地让它变成通过。)
  $5+10 CHF=$10 if rate is 2:1
  $5*2=$10
  Make “amount”private
  Dollar side-effects?
  Money rounding?
  刚刚敲进去的测试代码(在稍后讨论JUnit测试框架的时候,我会解释在哪里以及如何输入这些测试)甚至不能通过编译。这很容易修复。即使在测试无法运行的情况下,我们怎么能够做最少的工作而让测试通过编译呢?现在有以下4个编译错误:
  缺少“Dollar”类的定义。
  缺少构造方法。
  没有找到“Times(int)”方法。
  没有找到“amount”字段。
  让我们一个个地来解决上述问题(我在找一些可以数字化的进度测量值)。通过定义Dollar类,就能够消灭其中一个错误:
  Dollar
  class Dollar
  3个错误了。现在我们需要一个构造方法,它只需使测试能够通过编译,还不用做其他任何事情:
  Dollar
  Dollar(int amount){
  }
  2个错误了。我们需要一个times()方法的哑实现。再强调一下,我们将做尽可能少的工作来使测试通过编译:
  Dollar
  void times(int multiplier) {
  }
  1个错误了。这需要我们最终添加一个amount字段:
  Dollar
  int amount;
  搞定!现在我们可以运行这个测试并且看到它给出了失败的运行结果,如图1-1所示。
  图1-1 失败的运行结果
  你现在看到了令人担忧的红色指示条。测试框架(在这里指JUnit)运行了最初的那小段测试代码,而我们注意到了,期望的结果是“10”,实际的结果却是“0”。这是让人高兴不起来的。
  不能这么说,其实不是这样的,失败也是一种进步。现在我们有了对失败的具体判断。这总比只是含糊地知道我们的测试失败了要好。编程问题也从“提供多币种”变成了“让测试代码运行起来,而后让其他测试也运行起来”。更简单了。也不必有太多的担心,我们能够让这个测试运行起来了。
  也许你不太喜欢目前的解决方法,但是现在得到的并不是最佳答案,目标仅是通过当前的测试。稍后,我们会把事情做得更完美、更漂亮。
  下面是我可以想到的一点改动,它能使测试获得通过:
  Dollar
  int amount = 10;
  我们现在看到了令人感到愉悦的绿色指示条,如图1-2所示。
  图1-2 测试通过
  哦,快乐吧!哦,惊喜吧!别高兴得太早,淘气鬼。事情还没完呢。世界上很少能有什么输入会使得如此受限的、糟糕的、幼稚的实现就能通过测试。我们在继续前要将它泛化。请记住,周期如下:
  1. 添加一个测试。
  2. 运行所有的测试并查看失败的测试。
  3. 对测试进行微小的改动。
  4. 运行所有的测试并看到其通过。
  5. 通过重构去掉重复部分。
  依赖和重复
  Steve Freeman指出,测试和编码所包含的问题并不在于重复(重复的问题还没有解释,后面会尽快讲清楚)。问题在于编码与测试之间的依赖性—你不能更改它们其中之一而对另外的部分视而不见。我们的目的在于不对程序进行修改并且能够写出“讲得通”的测试,而这个用现在的实现方法是不可能做到的。
  依赖是各种规模的软件开发都会遇到的重要问题。如果某家供应商的数据库产品所对应的SQL语句实现细节散布于整个代码中,而你决定使用其他的数据库产品时,你会发现你的代码依赖于数据库产品供应商,你无法做到不改变程序代码而对数据库进行修改。
  如果依赖性是症结所在,那么重复则是所表现的症状。重复问题多数是以重复的逻辑呈现的,即相同的表达式在代码的多个地方重现。对象在将重复逻辑抽象掉这方面是很出色的。
  与生活中的大多数问题不同,后者将症状消除反而使问题在其他地方以更严重的形式出现,但在程序中消除重复部分的同时也可以消除依赖性。这也是测试驱动开发的第二条准则何以现身的原因。在继续下一个测试前,通过消除冗余,仅仅通过这一个步骤就让我们获得了使下一个测试得以通过的最大可能性。
  我们已经做了1~4项。现在准备去掉重复部分。但哪里是重复部分呢?你常常看到两段代码之间存在重复部分。而这里所讲的重复部分是测试中的数据与程序代码中的数据之间的重复。没看到吗?我们就来写一段如何呢?
  Dollar
  int amount = 5 * 2;
  上面的乘法结果的“10”一定来自于某个地方。在头脑中所做的乘法运算如此之快,我们甚至没有意识到。“5”和“2”现在位于两个不同的地方,在继续推进之前,我们要坚决地去掉重复部分。这就是规则。
  这里并不存在将“5”和“2”去掉的某个步骤。然而,如果我们将变量amount的设置从对象的初始化代码换到times()方法中会怎么样?
  Dollar
  int amount;
  void times(int multiplier) {
  amount = 5 * 2;
  }
  测试仍然可以通过,指示条还是绿色的。我们感觉也还可以。
  你是不是感觉这些改进微不足道?请记住,测试驱动开发的要点不在于采取了哪些措施,而在于能够取得这些微小进步本身。我们需要日复一日地编码从而完成这些细小的改进吗?当然不是,但当事情稍有不妥的时候,我很高兴我可以这样做。请自己选择一个示例并尽力对其完成细小的改进。如果你能够做到很小的改进,也一定可以完成你所需要规模的改进。如果只是做后者,那么你将永远不知道更小的改进是否合适。
  防御性的问题先放一边,我们刚才说到哪里了?哦,对,我们正在消除测试代码和程序代码之间的重复部分。从哪里可以得到“5”呢?如果我们把它存到amount变量中,那就成了传递给构造方法的值:
  Dollar
  Dollar(int amount) {
  this.amount= amount;
  }
  可以在times()方法使用变量amount:
  Dollar
  void times(int multiplier) {
  amount= amount * 2;
  }
  参数multiplier的值是2,那么我们可以用常量来替换这个参数:
  Dollar
  void times(int multiplier) {
  amount= amount * multiplier;
  }
  为了全面地体现Java语法知识,我们准备使用“*=”操作符(这样做其实可以减少重复的内容):
  Dollar
  void times(int multiplier){
  amount *= multiplier;
  }
  $5 + 10 CHF = $10 if rate is 2:1
  $5 * 2 = $10
  Make “amount” private
  Dollar side-effects?
  Money rounding?
  我们现在可以将第一个测试标记为完成。接下来要做的事情是关注这些奇怪的副效应。不过,首先需要检查已完成的事情:
  使一连串的已知并且所需的测试运行起来。
  描述了如何观察代码段所对应的操作。
  暂时忽略关于JUnit相关的细节。
  使测试代码的哑实现通过编译。
  通过极端的手段使测试运行。
  泛化程序代码,使用常量代替变量。
  将待办事项添加到列表中,而非毕其功于一役。
  ……
展开
目录
译者序
前言
致谢
引言
第一部分 货币实例
第1章 多币种货币实例
第2章 简并对象
第3章 定义相等性
第4章 实例变量私有化
第5章 法郎的自白
第6章 相等性再定义
第7章 美元和法郎
第8章 制造对象
第9章 正在进行的times方法
第10章 有趣的times方法
第11章 万恶之源
第12章 总算谈到加法了
第13章 到达我们的预期
第14章 变化
第15章 多币种货币
第16章 总算谈到抽象了
第17章 货币回顾

第二部分 xUnit实例
第18章 走进xUnit
第19章 设置主线
第20章 后续的清理
第21章 计数
第22章 处理未通过的用例
第23章 好美妙的测试套件

第24章 xUnit回顾
第三部分 测试驱动开发的模式
第25章 测试驱动开发模式
第26章 红条模式
第27章 测试模式
第28章 绿条模式
第29章 xUnit框架下的模式
第30章 设计模式
第31章 重构
第32章 掌握测试驱动开发

附录A 影响图
附录B 斐波那契数列
后记
展开
加入书架成功!
收藏图书成功!
我知道了(3)
发表书评
读者登录

请选择您读者所在的图书馆

选择图书馆
浙江图书馆
点击获取验证码
登录
没有读者证?在线办证