第Ⅰ部分 入门 3
第1章 单元测试的基本知识 3
1.1单元测试——传统定义 4
1.1.1编写“优秀单元测试”的重要性 5
1.1.2我们都写过单元测试(或多或少) 5
1.2优秀单元测试的特性 6
1.3集成测试 7
1.4优秀的单元测试——定义 11
1.5一个简单的单元测试实例 12
1.6测试驱动开发 16
1.7小结 19
第2章 第一个单元测试 21
2.1单元测试框架 22
2.1.1单元测试框架的优势提供了什么 22
2.1.2 xUnit测试框架 25
2.2 LogAn项目的介绍 25
2.3使用NUnit的第一步 26
2.3.1安装NUnit 26
2.3.2加载解决方案 27
2.3.3在代码中使用NUnit特性 29
2.4编写第一个测试 30
2.4.1 Assert类 31
2.4.2用NUnit运行我们的第一个测试 31
2.4.3修正代码让测试通过 32
2.4.4从红色到绿色 33
2.5更多NUnit特性 33
2.5.1 setup和teardown 33
2.5.2验证预期的异常 36
2.5.3忽略测试 39
2.5.4设置测试类别 39
2.6针对状态的间接测试 40
2.7小结 44
第Ⅱ部分 核心技术 49
第3章 使用桩对象解除依赖 49
3.1桩对象 50
3.2发现LogAn对文件系统的依赖 51
3.3确认简化LogAnalyzer测试的方法 52
3.4重构设计增强了可测性 54
3.4.1抽取接口,以允许替换底层实现 55
3.4.2在被测类中注入桩对象 57
3.4.3在构造函数级别上接收一个接口(构造函数注入) 58
3.4.4接收一个接口作为属性的get或set的类型 63
3.4.5在调用方法之前获取一个桩对象 65
3.5重构技术的变种 74
3.6解决封装问题 77
3.6.1使用internal和[InternalVisibleTo] 78
3.6.2利用[Conditional]属性标签 78
3.6.3使用#if和#endif的条件编译 79
3.7小结 80
第4章 用模拟对象做交互测试 83
4.1基于状态的测试和交互测试 84
4.2模拟对象和桩对象之间的区别 85
4.3简单的手写模拟对象例子 87
4.4同时使用模拟对象和桩对象 90
4.5一个测试一个模拟对象 95
4.6桩链:产生模拟对象或其他桩的一批桩对象 95
4.7手写模拟对象和桩对象的问题 97
4.8小结 97
第5章 隔离(模拟对象)框架 101
5.1为什么使用隔离框架 102
5.2动态创建伪对象 104
5.2.1在测试中引入Rhino Mocks 104
5.2.2使用动态模拟对象替换手写模拟对象 105
5.3严格模拟对象与非严格模拟对象 109
5.3.1严格模拟对象 109
5.3.2非严格模拟对象 109
5.4从伪对象返回值 111
5.5用隔离框架创建智能桩对象 113
5.5.1在Rhino Mocks框架中创建桩对象 113
5.5.2结合使用动态桩对象和模拟对象 115
5.6模拟对象和桩对象的参数约束 119
5.6.1用字符串约束检查参数 119
5.6.2使用约束检验参数对象的属性 121
5.6.3执行回调检验参数 124
5.7测试与事件相关的活动 126
5.7.1测试一个事件已被订阅 126
5.7.2在模拟对象和桩对象中触发事件 128
5.7.3测试一个事件是否被触发 129
5.8隔离框架中的设置-操作-断言语法 131
5.9 .NET中现有的隔离框架 135
5.9.1 NUnit.Mocks 136
5.9.2 NMock 136
5.9.3 NMock2 136
5.9.4 Typemock Isolator 137
5.9.5 Rhino Mocks 138
5.9.6 Moq框架 139
5.10隔离框架的优势 140
5.11避免使用隔离框架时的陷阱 140
5.11.1测试代码缺乏可读性 141
5.11.2对错误的事情做验证 141
5.11.3一个测试包含多个模拟对象 141
5.11.4测试的细节太多 142
5.12小结 143
第Ⅲ部分 测试的代码 147
第6章 测试层次及组织 147
6.1让自动化构建运行自动化测试 148
6.1.1自动构建剖析 148
6.1.2触发构建和持续集成 150
6.1.3自动化构建类型 150
6.2根据速度和类型组织测试 151
6.2.1分离单元测试与集成测试的人为因素 152
6.2.2绿色安全区域 153
6.3确保测试在代码库中 154
6.4在测试类和被测代码之间建立映射 154
6.4.1映射测试到项目 154
6.4.2映射测试到类 155
6.4.3映射测试到方法 156
6.5为应用程序打造测试API 156
6.5.1使用测试类的继承模式 157
6.5.2新建测试工具类和方法 175
6.5.3让程序员知道你的API 176
6.6小结 177
第7章 优秀单元测试的支柱 179
7.1编写可信赖的测试 180
7.1.1决定何时删除或更改测试 180
7.1.2避免测试的逻辑 186
7.1.3只测试一件事情 187
7.1.4让测试容易运行 188
7.1.5确保测试覆盖率 188
7.2编写可维护的测试 190
7.2.1测试私有的或者受保护的方法 190
7.2.2去除重复代码 192
7.2.3让Setup方法可维护 197
7.2.4实施测试隔离 200
7.2.5避免多个断言 208
7.2.6避免测试同一个对象的多个方面 212
7.2.7避免在测试里过度关注细节 215
7.3编写可读的测试 220
7.3.1为单元测试命名 220
7.3.2为变量命名 222
7.3.3让断言有意义 223
7.3.4将断言和动作分离 224
7.3.5 setup和teardown 225
7.4小结 226
第Ⅳ部分 设计与流程 231
第8章 在组织中引入单元测试 231
8.1怎样成为变革推动者 232
8.1.1备战棘手问题 232
8.1.2说服内部人士:拥护者与阻碍者 232
8.1.3洞察切入机会 234
8.2成功之路 235
8.2.1游击策略(自下而上) 235
8.2.2说服管理层(自上而下) 236
8.2.3从外面找一个专家 236
8.2.4让过程可见 237
8.2.5锁定目标 238
8.2.6意识到即将面对的阻碍 240
8.3失败之路 241
8.3.1缺乏驱动力 241
8.3.2缺乏政治上的支持 241
8.3.3不好的实施和第一印象 241
8.3.4缺乏团队支持 242
8.4棘手的问题及其答案 242
8.4.1在现有的流程上会增加多少时间 243
8.4.2测试人员的工作会因此受到威胁吗 245
8.4.3怎么知道这确实可行呢 245
8.4.4有什么可以证明单元测试的好处 246
8.4.5为什么测试部门还是能找到缺陷 246
8.4.6我们有很多没有测试的代码:该从哪里开始呢 247
8.4.7使用多种语言开发:单元测试适用吗 248
8.4.8如果是软硬件结合的开发,该怎么办 248
8.4.9怎么知道测试本身是否有缺陷 248
8.4.10我的调试器显示代码可以正常工作:为什么还需要测试 248
8.4.11必须用TDD的方式来编码吗 249
8.5小结 249
第9章 修改遗留代码 251
9.1从哪里开始添加测试? 252
9.2确定抉择策略 254
9.2.1容易优先策略的优缺点 254
9.2.2困难优先策略的优缺点 255
9.3在重构前写集成测试 256
9.4重要的遗留代码单元测试工具 258
9.4.1使用Typemock Isolator轻松隔离依赖项 258
9.4.2使用Depender找出可测性问题 260
9.4.3在Java遗留代码里使用JMockit 260
9.4.4重构Java代码时使用Vise 262
9.4.5使用FitNesse在重构前做验收测试 264
9.4.6阅读Michael Feathers的关于遗留代码的书 265
9.4.7使用NDepend来审查生产代码 265
9.4.8使用ReSharper浏览和重构生产代码 266
9.4.9使用Simian来检测重复代码(和缺陷) 266
9.4.10使用Typemock Racer来检测线程问题 267
9.5小结 267
附录A设计与可测试性 269
附录B工具和框架 281