测试驱动的面向对象软件开发

当前位置:首页 > 计算机网络 > 软件工程/开发项目管理 > 测试驱动的面向对象软件开发

出版社:机械工业出版社
出版日期:2010年8月
ISBN:9787111304258
作者:Steve Freeman,Nat Pryce
页数:253页

章节摘录

  这意味着在实践中我们可以把系统分成两个“世界”:值和对象。值以函数式的方式对待,对象则实现了系统有状态的行为。在第三部分,您会看到书中的编码风格是如何根据我们面对的世界而变化的。  在本书中,我们将使用术语“对象”来指具有标识符、状态和处理过程的实例,而不用于指值。似乎没有其他可以接受的术语同时包含这两种含义(如实体或过程)。  2.3 对象通信  只有当对象设计容易组合时,我们才能从这种高层次的、声明式的方式中获益。在实践中,这意味着它们遵循相同的通信模式,也意味着它们之间的依赖关系是显式的。通信模式是一组规则,决定了一组对象相互交谈的方式。这些规则包括它们扮演的角色、它们可以发送什么消息、何时可以发送等。在Java这样的语言中,我们可以利用(抽象的)接口来标识对象的角色,而不是利用(具体的)类——虽然接口不能定义任何我们想说的内容。  根据我们的观点,领域模型就在这些通信模型之中,因为正是它们为对象间可能的关系赋予了意义。以动态的、互相通信的结构来思考一个系统,这对于静态的分类来说是思考方式的巨大转变,而我们中的大多数人在刚接触对象时学到的都是静态的分类。领域模型甚至都不是明显可见的,因为在我们使用的编程语言中,通信模式没有明确表达出来。本书希望展示测试和模拟对象如何帮助我们更清楚地看到对象之间的通信。  这里有一个小例子,说明关注对象间的通信是怎样指导设计的。  在一个视频游戏中,对象可能包括:参与者(如玩家和敌人)、场景(玩家飞过的环境)、障碍(玩家遇上就会撞毁)、效果(如爆炸和烟雾)。还有一些脚本,它们在游戏过程中在后台大量生成对象。  从玩家的视角来说,这是一种很好的分类,因为它支持我们在玩游戏时需要做出的决定,也就是从外界与游戏进行交互时做决定。但是,对于实现这个游戏来说,这不是很有用的分类。游戏引擎必须显示可见的对象,告诉对象随时间产生动画效果,检测实体对象间的碰撞,并在实体对象发生碰撞时,把决定代理给碰撞处理器,如图2-2所示。  正如您在图2-2中看到的,这两种视角是不同的,一个是从游戏引擎的角度来看,另一个是从参与对象实现的角度来看。例如,障碍是可见的、实体的,而脚本是碰撞处理器和动画的,但不是可见的。游戏中的对象扮演了不同角色,取决于引擎当时对它们的需要。这种静态分类与动态通信之间的不匹配意味着,我们不太可能对游戏对象得到一个整齐的类层次结构,同时又能适合引擎的需要。  在最好的时候,类层次结构代表了应用的一个维度,它提供了一种机制,让对象之间能共享实现细节。例如,我们可能有一个基类来实现基于帧的动画的共同特征。在最坏的时候,我们曾看到许多代码库(包括我们自己的),充满了复杂性和重复,因为使用一种机制来表达多个概念。

前言

  随着软件发布周期越来越短,一个困境出现了:如何在更少的时间里发布更多的软件,并持续地发布下去?我们需要新的观点来解决这个困境。只有技术的转变是不够的。  本书展示了这样一个新观点——假如软件不是“做”出来的,不像我们做纸飞机那样,叠好后就飞出去,情况会怎样呢?假如我们像对待有价值、有产出的农作物那样(培育、剪草、收割、施肥和灌溉)对待软件,情况会怎样呢?几十年或几个世纪以来,传统的农夫知道如何让农作物高产。如果我们以同样的方式对待程序,软件开发会有什么不同呢?  我印象最深的是,本书同时提供了这种观点转变的哲学思想和实现机制。本书的作者是善于写代码的实践者,他们也善于教别人写代码。您从中可以学到如何保持高产,以及如何重新审视您的程序。  这里展示的测试驱动开发的方式不同于我所使用的方式。虽然我还不能清晰表达其中的区别,但我已从作者清楚、自信的技巧介绍中受益。方言的多样化已经为我进一步优化开发提供了思考的新源泉。本书展示了一个有条理的、一致的开发体系,其中的不同技巧相互支持。  我建议您阅读本书,通过书中的例子,了解作者如何思考编程,如何实践编程。这种体验将丰富您的软件开发方式,有助于您编程,而且同样重要的是,有助于您以不同的观点来看待您的程序。

媒体关注与评论

  “终于有一本书用丰富的代码揭示TDD和OOD之间的共生关系。本书值得保存。”  ——Robert C.Martin  “如果您想成为当前TDD领域的一名专家,就需要理解本书中的思想。”  ——Michael Feathers

内容概要

Steve Freeman和Nat Pryce是独立的软件顾问,他们是英国的敏捷软件开发先锋。他们都曾在一些行业和组织机构中工作过:电信业系统开发、金融业、体育新闻报道和市场传播、IBM的薄膜包装应用、工业和学术研究机构等。他们是伦敦XpDay的创始人和组织者,经常出席和组织国际会议。Steve和Nat是几个有影响的开源项目的贡献者,这些项目支持TDD。在2006年,他们共同获得了敏捷联盟的Gordon Pask奖。他们住在英国伦敦。

书籍目录

对本书的赞誉
译者序

前言
作者简介
致谢
第一部分简介
第1章测试驱动开发的要点
1.1软件开发是一个学习过程
1.2反馈是基本工具
1.3支持变化的实践
1.4测试驱动开发简介
1.5大局
1.6用户场景测试
1.7测试的级别
1.8外部品质与内部品质
第2章测试驱动开发与对象
2.1对象之网
2.2值与对象
2.3对象通信
.2.4吩咐,不要问
2.5但有时要问
2.6对协作的对象执行单元测试
2.7用模拟对象支持TDD
第3章工具介绍
3.1如果您已了解这些框架,可以跳过本章
3.2JUnit 4简介
3.2.1测试用例
3.2.2断言
3.2.3预期异常
3.2.4测试装置
3.2.5测试执行者
3.3Hamcrest匹配器和assertThat()
3.4jMock2: 模拟对象
第二部分测试驱动开发过程
第4章启动测试驱动循环
4.1简介
4.2先测试一个可行走的骨架
4.3决定行走的骨架的形状
4.4创建反馈源
4.5尽早暴露不确定性
第5章保持测试驱动循环
5.1简介
5.2每个特征都从一个验收测试开始
5.3分离测量进度的测试和捕捉回归
错误的测试
5.4从最简单的成功场景开始测试
5.5编写您愿意读的测试
5.6看着测试失败
5.7从输入开发到输出开发
5.8针对行为进行单元测试,而非针对
方法
5.9聆听测试
5.10调整循环
第6章面向对象风格
6.1简介
6.2为可维护性而设计
6.3内部与同级的比较
6.4没有“与”、“或”、“但是”
6.5对象同级构造型
6.6组合比它的部分之和更简单
6.7上下文无关性
6.8正确地隐藏信息
6.9固执己见的观点
第7章实现面向对象设计
7.1先写测试怎样有助于设计
7.2通信比分类更重要
7.3值类型
7.4对象来自何处
7.4.1分解
7.4.2萌芽
7.4.3打包
7.5利用接口确定关系
7.6接口也要重构
7.7组合对象以描述系统行为
7.8迈向更高层的编程
7.9关于类
第8章基于第三方代码构建
8.1简介
8.2只模拟您拥有的类型
8.2.1不要模拟您不能修改的类型
8.2.2编写一个适配层
8.3在集成测试中模拟应用对象
第三部分工作的例子
第9章委托开发一个拍卖狙击者
9.1从头开始
9.2与一次拍卖通信
9.2.1拍卖协议
9.2.2XMPP消息
9.3安全实现目标
9.4这不是真的
第10章可行走的骨架
10.1从壁橱中取出骨架
10.2我们的第一个测试
10.3一些初始选择
10.3.1用户场景测试
10.3.2准备开始
第11章通过第一个测试
11.1构建测试的装配
11.1.1应用执行者
11.1.2伪造的拍卖
11.1.3消息代理
11.2测试失败和通过
11.2.1第一个用户界面
11.2.2显示狙击者状态
11.2.3连接到拍卖
11.2.4从拍卖接收回应
11.3必需的最小实现
第12章准备竞拍
12.1对市场的介绍
12.2针对竞拍的测试
12.2.1从测试开始
12.2.2扩展伪造的拍卖
12.2.3令人吃惊的失败
12.2.4由外至内开发
12.2.5对细节的无限关注
12.3AuctionMessageTranslator类
12.3.1提取出一个新类
12.3.2第一个单元测试
12.3.3完成用户界面循环
12.3.4我们实现了什么
12.4解析价格消息
12.4.1引入消息事件类型
12.4.2第二个测试
12.4.3发现进一步的工作
12.5完成工作
第13章狙击者发出竞拍出价
13.1引入AuctionSniper
13.1.1一个新类及其依赖关系
13.1.2关注、关注、关注
13.2发送竞拍出价
13.2.1Auction接口
13.2.2AuctionSniper发出竞拍出价
13.2.3利用AuctionSniper成功竞拍
13.2.4用户场景测试通过了
13.3整理实现
13.3.1提取出XMPPAuction
13.3.2提取用户界面
13.3.3整理翻译者类
13.4延迟决定
13.5自然发生的设计
第14章狙击者赢得拍卖
14.1先写一个失败的测试
14.2谁知道竞拍者
14.3狙击者还有话要说
14.4狙击者需要某种状态
14.5狙击者获胜
14.6取得稳定的进展
第15章迈向真正的用户界面
15.1更现实的实现
15.1.1接下来我们该做什么
15.1.2替换JLabel
15.1.3还是很丑
15.2显示价格细节
15.2.1先写一个失败的测试
15.2.2狙击者送出状态
15.2.3展现竞拍狙击者
15.3简化狙击者事件
15.3.1跟着感觉走
15.3.2重新确定sniperBidding()的目标
15.3.3填入数字
15.4更进一步
15.4.1转换胜利和失败
15.4.2修整表模型
15.4.3面向对象的列
15.4.4缩短事件路径
15.5最后润色
15.5.1针对列标题的测试
15.5.2实现TableModel
15.5.3目前已足够
15.6短评
15.6.1单一职责
15.6.2软件微创手术
15.6.3程序员过敏症
15.6.4庆贺思维转变
15.6.5这不是唯一的解决方案
第16章狙击多项物品
16.1针对多项物品的测试
16.1.1两件物品的故事
16.1.2ApplicationRunner类
16.1.3偏离主题,改进失败信息
16.1.4重新设计Main的结构
16.1.5扩展表模型
16.2通过用户界面添加物品
16.2.1更简单的设计
16.2.2更新测试
16.2.3添加一个动作条
16.2.4设计时刻
16.2.5另一层次的测试
16.2.6实现UserRequestListener
16.3短评
16.3.1取得稳定的进展
16.3.2TDD的秘密
16.3.3发布它
第17章分解Main
17.1发现角色
17.2提取Chat
17.2.1分离Chat
17.2.2封装Chat
17.2.3编写一个新测试
17.3提取Connection
17.4提取出SnipersTableModel
17.4.1狙击启动者类SniperLauncher
17.4.2狙击组合
17.5短评
17.5.1增量式架构
17.5.2三点不动
17.5.3动态设计的同时也进行静态设计
17.5.4对notToBeGCd的另一种修复方法
第18章填充细节
18.1更有用的应用
18.2适可而止
18.2.1引入落后状态
18.2.2第一个失败的测试
18.2.3输入停止价格
18.2.4传送停止价格
18.2.5约束AuctionSniper
18.3短评
18.3.1增量式设计用户界面
18.3.2其他建模技术也有用
18.3.3领域类型比字符串好
第19章处理失败
19.1如果它不能工作
19.2检测失败
19.3显示失败
19.4断开狙击者
19.5记录失败
19.5.1填充测试
19.5.2翻译者中的失败报告
19.5.3生成日志消息
19.5.4完成这次开发循环
19.6短评
19.6.1 “切香肠的逆过程”式开发
19.6.2用一些小方法来表达意图
19.6.3日志也是一项功能
第四部分可持续的测试驱动开发
第20章聆听测试
20.1简介
20.2我需要模拟一个不能替换的对象
20.2.1单例是依赖关系
20.2.2从过程到对象
20.2.3隐式依赖也是依赖
20.3记日志是一项功能
20.3.1通知而不是记日志
20.3.2但这种想法很疯狂
20.4模拟具体的类
20.5不要模拟值类型
20.6膨胀的构造方法
20.7令人困惑的对象
20.8太多依赖关系
20.9太多预期
20.10测试会告诉我们什么
第21章测试可读性
21.1简介
21.2测试名称描述功能
21.3规范的测试结构
21.4精简测试代码
21.4.1用结构来解释
21.4.2利用结构来共享
21.4.3强调正面
21.4.4代理给从属对象
21.5断言和预期
21.6具体值和变量
第22章构造复杂的测试数据
22.1简介
22.2测试数据建造者
22.3创建一些类似的对象
22.4组合建造者
22.5利用工厂方法强调领域模型
22.6从使用的角度消除重复
22.6.1首先,消除重复
22.6.2然后,让游戏升级
22.7沟通第一
第23章测试诊断
23.1要的就是失败
23.2小、专注、良好命名的测试
23.3解释性断言消息
23.4利用匹配器对象来突出细节
23.5自描述的值
23.6明显的预装值
23.7跟踪者对象
23.8明确断言预期得到满足
23.9诊断是一级功能
第24章测试的灵活性
24.1简介
24.2针对信息测试,而非针对表示方法
24.3准确断言
24.4准确预期
24.4.1准确的参数匹配
24.4.2允许和预期
24.4.3忽略不相关的对象
24.4.4调用次序
24.4.5jMock States的威力
24.4.6更为自由的预期
24.5“豚鼠”对象
第五部分高 级 主 题
第25章测试持久性
25.1简介
25.2隔离影响持久状态的那些测试
25.3明确测试的事务边界
25.4测试一个执行持久操作的对象
25.5测试对象能够持久
25.5.1来回转换持久对象
25.5.2来回转换相关的实体
25.6但数据库测试很慢
第26章单元测试与线程
26.1简介
26.2分离功能和并发策略
26.2.1并发地搜索拍卖
26.2.2引入Executor
26.2.3实现AuctionSearch
26.3对同步进行单元测试
26.3.1针对AuctionSearch的压力测试
26.3.2两次修复竞争条件
26.4对被动对象进行压力测试
26.5同步测试线程和后台的多线程
26.6单元压力测试的局限性
第27章测试异步代码
27.1简介
27.2取样或监听
27.3两种实现
27.3.1捕获通知
27.3.2轮询变更
27.3.3超时
27.3.4改进探测类
27.4轻易成功的测试
27.5错过更新
27.6测试没有效果的活动
27.7区分同步和断言
27.8事件源外部化
后记模拟对象简史
附录AjMock2速查手册
附录B编写Hamcrest Matcher
参考文献

编辑推荐

  《测试驱动的面向对象软件开发》对于更快交付更好的软件,测试驱动开发(TDD)现在是一种已经确立的技术。TDD基于一个简单的思想:在写产品代码之前先写它的测试代码。但是,这个“简单”的思想需要一些技能和判断才能做得好。现在有了一本TDD实践指南。让您深入理解那些基本概念,并向您展示了如何让测试来引导开发,“培育”出一致的、可靠的。可维护的软件。  作者描述了他们使用的过程,努力实现的设计原则。以及完成工作的一些工具。通过一个详细实现的例子,您可以看到TDD如何在各个层次上工作,如何利用测试来驱动特征开发和代码的面向对象结构,如何利用模拟对象来发现并描述对象之间的关系。在这个过程中。《测试驱动的面向对象软件开发》系统地讨论了开发团队在使用TDD时遇到的挑战——从过程中集成TDD到测试最难的特征。  旧代码带来的新思维,Robert C.Martin高度评价,Kent Berk作序推荐。  《测试驱动的面向对象软件开发》包括以下内容:  ●如何有效实现TDD:启动,然后在整个项目中保持你们的冲劲。  ●如何创建更干净的、更有表现力的、更可维护的代码。  ●如何利用测试。对可持续的品质保持最严格的关注。  ●理解在真实软件开发的环境中,TDD、模拟对象、面向对象设计如何交织在一起。  ●如何利用模拟对象来指导面向对象设计。  ●如何在TDD困难的地方取得成功:管理复杂的测试数据。测试持久层和并发。

作者简介

《测试驱动的面向对象软件开发》采用通俗易懂的比喻,众所周知的编程语言,短小精悍的工作实例,深入浅出的分析处理——仿佛在和几位世界级的编程高手一边喝茶,一边聊天,循序渐进地让读者在不知不觉中进入编程的最高境界。即使是刚刚入门的初学者,也会从中找到读书的乐趣,因为可以从一开始就找到开启面向对象开发大门的钥匙;随着经验的积累,编程水平的提高,再来看这本书,用不同的视角重新审视程序,又会体会到更深层的编程哲学。
本书是编程爱好者的启蒙指南,更是系统分析人员、测试人员、程序设计人员、软件开发人员以及面向对象程序研究人员等专业人士革新编程思想的必备手册。

图书封面


 测试驱动的面向对象软件开发下载 精选章节试读 更多精彩书评



发布书评

 
 


精彩书评 (总计4条)

  •     例子有些过于复杂,再加上代码没有有效组织,很容易迷路。书中甚至没有提到代码的下载。建议学习《单元测试的艺术》,更为清晰。建议学习《单元测试的艺术》,更为清晰。建议学习《单元测试的艺术》,更为清晰。建议学习《单元测试的艺术》,更为清晰。建议学习《单元测试的艺术》,更为清晰。
  •     有很多书说过要写好的代码,代码要高内聚,低耦合。代码要符合SOLID原则。我们都知道这些说教,这些原则;但是,我们如何才能知道我写的一段代码不好呢,原则往往漂浮在理论层次,理论来源于实践,但是高于实践。我们必须需要一些“硬指标”来衡量我的代码,为什么说这段代码是不好的呢?所以我们必须找到一些信号。这些信号可以来自哪里,测试就是其中一个信号源。1、一段代码难以测试?需要构建很多其他对象,然后才能实例化这个对象?请你务必检查一下这个对象的职责是否单一。2、一段代码难以测试?需要构建一些很难构建的对象,而这些对象由不受我们的控制。请你务必检查一下我们是否需要对这些我们没法控制的难以创建的对象进行抽象,进行适配。3、很难给一个测试方法起名字?是否意味着被测试的方法功能不明确或者职责太多。我已经读完了本书的第一、二以及四部分,我就觉得收获良多,如果你想实行测试驱动开发,那么这本书绝对是你的良师益友。唯独有点缺陷的是,本书翻译不是很通顺,有些地方稍显生硬,不过绝对不影响阅读,我是这么觉得~~~
  •     比Robert C. Martin, Martin Fowler的书都要好。作者的见解极为深刻。非常适合有基本面向对象素养的工程师阅读。大多数人都吐槽例子不够好,太复杂太细,而且没有源代码下载。不过我倒认为贯穿本书的例子非常非常好。

精彩短评 (总计27条)

  •     比较泛,感觉不好
  •     作者功力深厚,翻译有待改进
  •     少有的面向对象的测试驱动书籍
  •     看了一点点,书中用的讲解的例子挺高深的
  •     书还不错,翻译嘛,只能算一般般……
  •     上次帮 @Sherry陈怡 买的,今天翻了一下,TDD结合java 开发讲得相当不错,推荐看看。@王海鹏Seal 翻译的,质量有保证。
  •         这本书2009年10月就出来了,当时没来得及细看,只是把它放入了我的待读列表中。后来查到2010年8月也出了中文版,书名叫《测试驱动的面向对象软件开发》。看完全书后,我发现本书重点谈的还是软件培养问题。Growing这个词出现在书的标题中,非常吸引我的思路。
      
        在前言中,作者开宗明义,讲了本书要强调的五个问题:1.如何让测试驱动开发适应我的工程;2.从那里开始做TDD;3.如何写单元测试与端对端测试;4.测试驱动开发的“驱动”是何意;5.如何测试某一个困难的功能。
      
        第一部分是简介。导言部分说了,TDD不仅是XP(极限编程)的核心实践,而且也被Crystal Clear,Scrum等敏捷开发方法才用。敏捷和非敏捷项目都可应用TDD,甚至是纯研究项目都可以。
      
        第一章重申TDD的纪律——“在没有一个失败的用例之前,不要写任何功能”。其后提出,将传统的“测试-实现-重构”小迭代外面,包上一个验收测试(Acceptance Test)。验收测试是测试整个系统是否能工作的。与之区别的是用于测试现有代码与我们不能改变其代码的模块是否能配合工作的集成测试(Integration Test),以及测试对象本身功能的单元测试(Unit Test)。最后强调了单元测试能够给我们一个发现不良设计以及重构代码的机会。
      
        接下来第二章讲述了“值类”和“对象类”的区别。针对不变的数量和度量进行建模,就是“值类”,它有些类似“不可变类”(Immutable Class)或者无状态(Stateless)类。如果针对行为进行建模,则是“对象类”了。最后讲述了要使用单一的“告知型”调用代替请求式的一连串调用,例如用“master.allowSavingOfCustomisations();”来代替“((EditSaveCustomizer)master.getModelisable().getDockablePanel().getCustomizer()).getSaveItem().setEnabled(Boolean.FALSE.booleanValue());"。第三章介绍了一些TDD的基本工具。
      
        第二部分讲述了TDD的具体过程。第四章讲了如何确定测试驱动开发的第一个迭代周期。提出先实现最少量的真实功能以便可以自动地构建、部署、端对端测试。这叫做“行走骨架”(Walking Skeleton),具体的说,是通过“理解问题->设计草图->自动化构建,部署,端对端测试->普通迭代”这个流程来做的。其后说道,测试先行的工程早起会引入混乱,但是迅速降低,因为找到了发展的方向,预见了可能发生的错误。相反,测试后行(或到发布期限前才集成)的工程在最后会出现大量的混乱。这可以作为是否选取TDD的一个参考标准。而“行走骨架”的好处就是,能让我们在仍有时间、预算和解决问题的意愿时,去解决问题,而不至于到了发布前才发现工程已经失控。
      
        第五章讲了如何维护测试驱动周期。作者提出,将衡量进度的测试(针对新功能的验收测试)和用以捕捉“功能破坏”(Regression)的测试(已有的验收测试、整合测试、单元测试)分隔开来。“笔者注:广义的回归测试即为了保证正在开发的新功能不破坏既有功能而写的测试,狭义的回归测试专指前述的验收测试。”此后提到两个问题,一是不要着急写单元测试,以免整合时发现功能不符合需要,二是要学会“倾听测试”——难于测试的功能往往意味着设计需要改进。如不改进,如果功能增多,则该有问题的设计会更难于修改。
      
        第六章讲述了如何在TDD中使用面向对象的风格。作者讲述了Cockburn的“端口与适配器”架构,业务领域的代码应该同技术设施,例如数据库,UI等,分离开来。不要让技术概念泄漏入应用程序模型。所以要通过接口将应用程序核心业务与每个技术领域桥接起来。这就是Eric Evans在《领域驱动设计》中所说的防腐层(Anticorruption Layer)。其后又讲了封装和信息遮掩的区别。封装主要是相对于“对端”(Peer)来说的,强调访问只能通过API进行。而信息遮掩主要是针对上层业务来说的,意在使得高层逻辑不需关注低层细节。封装和信息遮掩中的两个常见问题即是通过API返回内部实现而产生的“别名”效果。以及没能提供直接的API调用,导致客户代码通过自己组合API来完成任务,就像前述的一连串调用那样,暴露了过多细节。接下来讲了达成“单一责任原则”的一个口诀:不用任何连词(和,或,但)去描述对象。如果有从句,那么应该按照从句,把大对象拆分成一个个互相合作的小对象。这对于我们检视自己的设计很有帮助。作者将设计中一个对象的协作者,分为三种角色模板。即依赖其服务方能运转的“依赖物”(Dependencies),用于通知事件而不关注其具体身份的“被通知物”(Notifications),以及利用其调整自身行为以符合系统需求之“调整物”(Adjustments)。其后作者讲了“组合体对象”(笔者注:即组合各种对象来完成自身任务的功能模组,不同于设计模式中的组合体模式)所提供的API要比其各自部分的API总和简单。它封装了组件的存在及其内部互动,为其对端展示出一个更简单的抽象接口。本章的最后讲述了“环境独立性”的重要。“环境独立性”规则帮我们判断一个对象是否隐藏的太多或者隐藏了错误的信息。当执行环境变化时,环境独立的对象是易于改变的。其运行大环境可以通过构造器(如果对于该对象是贯穿生命期的)或需要环境的方法(如果是瞬态的)传入。
      
        第七章继续讲述如何达成面向对象的设计。首先讲述TDD对OO设计的帮助:1.我们必须先描述我们要做什么,而后才是怎么做;2.为了使得单元测试易懂(由此变得可维护),我们必须限定它们的范围(笔者注:如果单元测试过长或者setup阶段太繁复,则意味着受测的那个大对象需要拆解);3.我们必须将其依赖物传给它,这意味着我们必须知道它依赖的都是些什么东西。再说了接口和协议的作用:接口描述了两个组件是否互相适配,而协议则描述了他们是否能一起运转。又讲了测试可以帮助我们发现设计中的问题:一个杂乱或不清晰的测试暗示着我们暴露了太多实现,而且我们应该重新考量该对象及其临接物件的责任分配。在讲到值类和对象类的设计时,作者提出了三个技巧:打散(将一个大对象分割成一组互相协作的小对象)、剥离(定义一个对象所需的新服务,增加一个提供该服务的新对象)、捆绑(将相关对象藏入一个容器对象中)。最后在谈到接口问题时,作者提出了两个观点。一个说道:针对某一个接口的实现而写的Impl类是没有意义的。如果实现类真的没有一个好名字,那可能意味着接口的命名或者设计很糟。可能它因为有太多的责任而丧失了重点;也可能它是以实现的角度命名,而非以其在客户代码的角度上;又或者它是一个值而非一个实体对象——这种不协调有时会在写单元测试时呈现出来。(例如MyInteger和MyIntegerImpl这种接口分离就是很糟糕的)另一个说:应该根据需要合并或者拆分接口。在发现实现类的结构不清晰时,应考虑接口是否没有侧重点,需要拆解。
      
        第八章讲如何在第三方代码之上构建自己的工程。作者建议写一个适配器对象层,其使用第三方API实现它们的接口。我们用有重点的集成测试去测试这些适配器,以确认我们理解了第三方API是如何工作的。
      
        第三部分讲了一个例子,用开发一个捕捉拍卖行情而自动出价的竞拍器,来说明如何以测试为指导,去培养OO软件开发。本部分跨越了十一章。在这个过程中,穿插着对前两章所讲原则的实例化运用。第十一章演示了如何用最少的代码搭建起来可以执行的端对端测试。在本例中,仅有一个测试用空壳服务器,一个Swing窗口(最少的代码),主程序向“服务器”发送加入消息,核实服务器确实收到消息;服务器关闭竞拍,窗口显示失败消息,核实窗口确实显示了失败消息(可执行的端对端测试)。第十二章对如何组织测试提出了小建议:将测试放在一个不同的包中。防止通过包级别的后门去测试,同时方便在IDE中浏览。第十五章讲述了修改命名的重要性:重命名代码中的若干功能,这是开发进程的一个重要部分,就像我们可以用已经写出的代码来更好地理解结构应该如何发展一样,我们也通过用已经修改过的名字去编程以更好地理解这些名字的意义。我们可以理解类型和方法名是如何互相配合起来工作的,以及概念是否清晰,这都会激发我们发现新的想法。如果一个功能的名字不对,唯一能做的明智事情就是改变它,以免过后阅读代码的人花了数不清的时间也弄不清代码在干什么。第十七章说到静态设计和动态设计的问题:重构非常关注于静态结构(类与接口),以至于很容易忽略应用程序动态结构(实例与线程)。有时我们需要退一步考虑,去画一个类似互动图那样的东西。其后的第十八章说道TDD应该和其它的建模手段结合起来使用,并且不要把其它的建模技巧当作一种目的,而是要理解它们,并且把它们当作支持与指导开发的一种手段。最后第十九章说我们必须知道如何渐进式的改变代码,尤其是使得代码结构良好,以至于我们可以根据需求的改变把代码带我们想去的地方。
      
        第四部分标题“可持续的测试驱动开发”,意为教大家如何提高测试的质量,以便让测试能够更及时、更好地提供关于设计缺陷的反馈。第二十章讲了几个知识点。当我们在测试驱动开发的过程中提取一个接口,我们就必须想出一个名字来描述刚刚发现的关系。我们觉得这使我们深入思考领域问题,并梳理出可能会错过的概念。只覆写可见的方法(即保护的和公有的)。这个规则防止了仅仅为了测试能覆写而暴露了内部方法。在谈到模仿对象(Mock Object)时,作者说有两个试探法可以决定一个类是不是像值类从而不值得去仿造它。第一,它的值是不可变的;第二,我们想不出来一个有意义的名字来描述把这个类当作接口之后,实现它的那个类。在对付膨胀的(参数过多的,过于复杂的)构造器时,作者提出可以提取出隐含的组件。其要寻找两个条件:经常在类里一起使用的参数;拥有相同生命期的参数。当我们刚好找到了这种情况时,就得努力想出一个好名字来解释这个概念。一个做得好的设计,其标志之一即是这种改变可以很容易集成进来。我们坚持依赖物应该通过构造器传入,但是被通知物和调整物可以设置为缺省值,稍后再行配置。当一个构造器太大了,并且我们不认为参数中隐含有一个新的类型时,我们可以用更多的缺省值,仅在有特殊的测试用例时才覆盖掉它们。在谈到期望陈述时,作者说要避免太多的期望。如果我们有很多期望,要么就是视图测试一个过于庞大的单位,要么就是锁定了太多的对象交流行为。作者还谈到了倾听测试给我们带来的四个好处:使领域知识局部化;将对象间的关系抽象并命名成类;通过定义类型和角色而带来更多的名字,就意味着带来更多的领域信息;与其提供数据,不如提供行为。本章最后总结说:测试驱动开发是低容忍度的。低质量的测试会使得开发速度变得非常慢,而且受测系统内部代码质量低的话,会导致测试的质量也跟着变低。
      
        第二十一章讲了测试的可读性问题。以下五种情况应当改进:1.测试名称没有清晰的描述出每个测试用例的重点,以及它和其余测试用例的差别;单一的测试用例执行了多个功能;测试用例间的结构差异很大,以至于读者不能通过速读来理解它们的意图;过多的设置和异常处理代码,将业务逻辑淹没其中;测试使用了不明其意的字面值(魔法数字)。在讲到如何命名测试时,作者介绍了TestDox约定法,即使每一个名字读起来像一个句子,其隐含主语即为测试目标,例如:A List holds items in the order they were added. A List can hold multiple references to the same item. A List throws an exception when removing an item it doesn’t hold.即可翻译成三个测试方法的名称:holdsItemsInTheOrderTheyWereAdded(),canHoldMultipleReferencesToTheSameItem(),throwsAnExceptionWhenRemovingAnItemItDoesntHold()。在变量的命名上,作者强调我们应该用能够显示这些值或者对象在测试中所扮演的角色以及他们同目标对象的关系的名字来命名。
      
        第二十二章讲了如何构建复杂的测试数据。测试数据构建器的一个好处是,我们可以写出易于阅读且便于发现错误的测试代码,因为每个构建器方法都指明了它的参数的意图。
      
        第二十三章讲述了如何从测试失败信息中演进工程代码。作者说,就算是发生在和我们现在所做无关的领域里面,未预期的测试失败,也可能是有价值的。因为它们揭示了代码中我们所未注意到的隐含关系。如果一个失败的测试清楚的解释了失败的东西和原因,我们就可以快速的排查并修正代码。同时作者建议,“经常同源代码库同步——可以到隔几分钟就一次的频度——以便一旦一个测试突然失败了,你不需要花费多长时间就能撤销最近的修改,并去尝试另一个方法。……比起一直查错,有时候回滚代码并以一个清晰的头脑重新思考“如何去写”,可能会更快。”
      
        第二十四章讲了测试的灵活性。如果一个对象因为有太多的依赖物或者其依赖物是隐藏的,从而很难从它的环境中解耦,那么当系统的某个偏远角落改变了,测试就会失败。
      
        最后的第五部分讲述了一些高级话题,第二十五章讲述了持久化。作者提出将影响持久化状态的测试孤立开来。将执行持久话操作的测试和针对被持久话对象进行的测试分开来做。并且提及一个小技巧:不要以模式来命名类或者接口,它们与系统其它类之间的关系才是重要的。当它们的工作方式改变时,这样做会使得名称具有误导性。第二十六章讲述了单元测试和线程。作者提出,并发是一个系统级别的关注点,我们应该在需要执行并发任务的对象“功能对象”之外来操控它。最后第二十七章讲述了测试异步代码的问题。作者指出,一个测试可以有两种方式观察系统:采样可被观测的状态或者监听它发出的事件。同时还指出了异步测试的一个注意点:测试可能会在系统之前运行以至于没有测试任何有用的东西。这会造成貌似正确的结果:错误的代码看起来好像能正常运行。还提出,采样测试与监听事件测试的一个明显区别是,轮询可能会错过被新近状态所覆盖掉的状态更新。解决办法是,可以查找记录。触发一个刺激事件,并等系统状态稳定再查询。作者又提出,我们经常采用一个命名方案去区分同步与断言。例如waitUntil()是等待某一个受测系统稳定(同步代码),而assertEventually()则是断言某个事件最终会发生。本章最后作者讲述了测试排期事件的问题。通过将事件排期机制从系统中解耦,可以使得系统的行为具有确定性从而更易测试事件。我们可以将事件的生成抽取成一个由外部驱动的共享服务。
      
        本书的跋很值得一读。写了整个jMock从构想,初创,演进到巩固的过程。起初是为了方便测试某一个对象内部的功能机制是否如我们预期,后来逐渐把关注点从参数的值转移到了对象之间的信息沟通上。现在jMock已经成为一个单元测试和验收测试中进行期望陈述与断言的常用库了。读者有必要熟悉并掌握它。最后的两个附录讲了jMock2库和Hamcrest匹配器的使用方法,如果对书前面的范例代码中的用法不太熟悉,可以参考。
      
        总的说来,在读此书的过程中我非常惊喜,发现尽管TDD有很多令人诟病的缺点,但是仍然有人和我想像一样,用不瘟不火的稳健心态来创造性的加入“培养”要素,以使得TDD对工程开发有更大的促进作用。测试是一个良好的反馈来源,可以真实的反映出我们在设计中考虑不周到之处,以及时督促我们改进产品代码的设计。要想让测试能够如此培养软件的开发,就必须着力于测试代码的先行性、正确性、可读性与灵活性。同时要注意用验收测试来催生新的迭代周期,在修改代码时不仅要运行单元测试,更要及时运行验收测试以获得更多回馈。我想信,用心于测试的努力,必能在产品代码的研发中产生加倍的回报。
      
      本文为原创,如需转载请联系作者(Email eastarstormlee@gmail.com 微博 http://weibo.com/eastarlee)
  •     后面的实例部分没读,TDD的书籍是不是都没有以web app为例子讲述的?
  •     JUnit, JMOCK, HAMCREEST
  •       本书作者是Mock技术的早期创始人,对OO理论和TDD的理解很深。读本书不仅是学习TDD,更是学习OO思想和方法。相比Kent Beck的《TDD by Example》本书要好一个档次。
  •     又懂了点儿java, 模拟对象周围都没人用
  •       书很薄,思想很丰富,结合了TDD思想与OOD思想的融合,还介绍了JMOCK2、HAMCREEST、JUnit4三个最有价值的工具。作者10余年的TDD经验指导性很强,堪称神作。
      
      我相信它可以提升你至少一个档次!
  •     Useful but boring. If you think it's interesting, just go ahead.
  •       例子有些过于复杂,再加上代码没有有效组织,很容易迷路。书中甚至没有提到代码的下载。
      
      
      建议学习《单元测试的艺术》,更为清晰。
      
      建议学习《单元测试的艺术》,更为清晰。
      
      建议学习《单元测试的艺术》,更为清晰。
      
      建议学习《单元测试的艺术》,更为清晰。
      
      建议学习《单元测试的艺术》,更为清晰。
      
  •     刚看了几眼 感觉还行吧~
  •     迄今为止最好的程序设计方面的书籍,没有之一。
  •     又一本重量级的tdd书,希望实践意义大一些
  •     看过,由于对java不熟悉,最精华的实例讲解部分看的很粗。 基本思想不错,前面几个章节内容也很精炼。 有空时,还要再细看看。 收获: 尽可能的减少对象间的依赖,分清对象之间的关系。 重构在编码中应该得到重视,通过编码来完善之前的结构设计。
  •     不只是测试,更多的是设计,不错
  •     适合考古,跳过了中间大段 java 的例子
  •     星太少了,
  •     搞活动时买的超值
  •       有很多书说过要写好的代码,代码要高内聚,低耦合。代码要符合SOLID原则。我们都知道这些说教,这些原则;但是,我们如何才能知道我写的一段代码不好呢,原则往往漂浮在理论层次,理论来源于实践,但是高于实践。我们必须需要一些“硬指标”来衡量我的代码,为什么说这段代码是不好的呢?所以我们必须找到一些信号。
      这些信号可以来自哪里,测试就是其中一个信号源。
      1、一段代码难以测试?需要构建很多其他对象,然后才能实例化这个对象?请你务必检查一下这个对象的职责是否单一。
      2、一段代码难以测试?需要构建一些很难构建的对象,而这些对象由不受我们的控制。请你务必检查一下我们是否需要对这些我们没法控制的难以创建的对象进行抽象,进行适配。
      3、很难给一个测试方法起名字?是否意味着被测试的方法功能不明确或者职责太多。
      
      我已经读完了本书的第一、二以及四部分,我就觉得收获良多,如果你想实行测试驱动开发,那么这本书绝对是你的良师益友。
      唯独有点缺陷的是,本书翻译不是很通顺,有些地方稍显生硬,不过绝对不影响阅读,我是这么觉得~~~
  •     早就听说过TDD在程序开发中的重要性,限于时间,一直未能好好的学习一下该项技术。现在终于到了学习TDD的时候了,就从本书开始我的TDD之旅吧!
  •     翻译的一般,不怎么通顺。例子采用Swing GUI,并不是很好。
  •     这本书有两大看点,一是如何执行测试驱动的开发,二是面向对象的软件设计,都融合实例演绎的非常透彻,十分推荐。
  •     书还凑合,纸张有点弱,不影响阅读,还行
 

外国儿童文学,篆刻,百科,生物科学,科普,初中通用,育儿亲子,美容护肤PDF图书下载,。 零度图书网 

零度图书网 @ 2024