第1章 环境设置 1
1.1 开场白 1
1.2 示例程序 1
1.3 C++编译器 2
1.3.1 Ubuntu 2
1.3.2 OS X 2
1.3.3 Windows 3
1.4 CMake 4
1.5 Google Mock 5
1.5.1 安装Google Mock 5
1.5.2 创建main函数运行Google Mock测试 7
1.6 CppUTest 7
1.6.1 安装CppUTest 7
1.6.2 创建main函数以运行CppUTest测试 8
1.7 libcurl 8
1.8 JsonCpp 8
1.9 rlog 9
1.10 Boost 10
1.11 构建示例并运行测试 10
1.12 结束语 11
第2章 测试驱动开发:第一个示例 12
2.1 开场白 12
2.2 Soundex类 12
2.3 开始吧 13
2.4 去掉不干净的代码 19
2.5 增量性 21
2.6 fixture与设置 23
2.7 思索与测试驱动开发 25
2.8 测试驱动与测试 28
2.9 如果出现别的情况呢 30
2.10 一次只做一件事 31
2.11 限制长度 32
2.12 丢掉元音 34
2.13 让测试自我澄清 34
2.14 跳出条条框框来测试 36
2.15 言归正传 38
2.16 重构至单一责任的函数 39
2.17 收尾工作 40
2.18 漏了什么测试吗 41
2.19 解决方案 42
2.20 Soundex类 43
2.21 结束语 46
第3章 测试驱动开发基础 47
3.1 开场白 47
3.2 单元测试和测试驱动开发基础知识 47
3.2.1 单元测试的组织和执行 47
3.2.2 测试驱动单元 48
3.3 测试驱动开发周期:红—绿—重构 49
3.4 测试驱动开发的三条准则 50
3.5 表里不一 51
3.5.1 运行了错误的测试 52
3.5.2 测试了错误的代码 52
3.5.3 不当的测试规范 53
3.5.4 对系统的无效假设 53
3.5.5 不佳的测试顺序 53
3.5.6 相关联的产品代码 56
3.5.7 过度编码 58
3.5.8 确定性测试 59
3.5.9 停下来想一下 59
3.6 成功运用测试驱动开发的思维 59
3.6.1 增量性 59
3.6.2 测试行为而非方法 60
3.6.3 使用测试来描述行为 60
3.6.4 保持简单 61
3.6.5 恪守测试驱动开发周期 62
3.7 成功运用测试驱动开发的方法 62
3.7.1 下一个测试是什么 62
3.7.2 十分钟限制 64
3.7.3 代码缺陷 64
3.7.4 禁用测试 65
3.8 结束语 66
第4章 测试结构 67
4.1 开场白 67
4.2 组织方式 67
4.2.1 文件组织 67
4.2.2 fixture 68
4.2.3 Setup与Tea rdown 69
4.2.4 Arrange-Act-Assert/Given-When-Then 72
4.3 快速测试、慢速测试、过滤器和测试集 73
4.4 断言 75
4.4.1 经典的断言形式 76
4.4.2 Hamcrest断言 76
4.4.3 选择正确的断言 78
4.4.4 浮点数比较 78
4.4.5 基于异常的测试 79
4.5 探查私有成员 81
4.5.1 私有数据 81
4.5.2 私有行为 82
4.6 测试和测试驱动:参数化的测试及其他方法 85
4.6.1 参数化测试 85
4.6.2 测试中的注释 87
4.7 结束语 87
第5章 测试替身 88
5.1 开场白 88
5.2 依赖问题 88
5.3 测试替身 89
5.4 手动打造的测试替身 90
5.5 在使用测试替身时提升测试的抽象程度 94
5.6 使用模拟对象工具 96
5.6.1 定义一个派生类 96
5.6.2 设立期望 97
5.6.3 松模拟和严模拟 100
5.6.4 模拟对象中的顺序 101
5.6.5 巧妙的模拟工具特性 102
5.6.6 排除模拟失败 104
5.6.7 一个还是两个测试 104
5.7 让测试替身各就各位 105
5.7.1 覆写工厂方法和覆写Getter 105
5.7.2 使用工厂 107
5.7.3 通过模板参数 109
5.7.4 注入工具 110
5.8 设计会变化 110
5.8.1 内聚与耦合 110
5.8.2 转嫁私有依赖 112
5.9 使用测试替身的策略 113
5.9.1 探索设计 113
5.9.2 mock流派 114
5.9.3 明智地使用测试替身 115
5.10 其他关于测试替身的主题 115
5.10.1 怎么称呼它们 116
5.10.2 测试替身该放在哪 116
5.10.3 虚函数表和性能 117
5.10.4 模拟具体的类 117
5.11 结束语 118
第6章 增量设计 119
6.1 开场白 119
6.2 简单设计 119
6.2.1 重复代码的代价 120
6.2.2 投资管理器 120
6.2.3 投资管理器中的简单重复 122
6.2.4 我们真的能坚持增量方法吗 124
6.2.5 更多的重复 129
6.2.6 小方法的好处 132
6.2.7 完成功能 134
6.2.8 增量设计让事情变得简单 138
6.3 预先设计在哪 141
6.3.1 哪里才会讨论真正的设计呢 142
6.3.2 简单设计原则和经典设计理念会在哪起冲突 143
6.4 阻碍重构的因素 143
6.5 结束语 145
第7章 高质量测试 146
7.1 开场白 146
7.2 测试先行 146
7.2.1 快速 146
7.2.2 独立 148
7.2.3 可重复 149
7.2.4 自我验证 150
7.2.5 及时 150
7.3 一个测试一个断言 150
7.4 测试抽象 153
7.4.1 臃肿的初始化 153
7.4.2 不相关的细节 154
7.4.3 缺失的抽象 156
7.4.4 多重断言 157
7.4.5 不相关的数据 157
7.4.6 不必要的测试代码 158
7.5 结束语 164
第8章 遗留代码的挑战 165
8.1 开场白 165
8.2 遗留代码 165
8.3 法则 166
8.4 遗留应用程序 167
8.5 保持测试驱动开发的心态 170
8.6 支持测试的安全重构 171
8.7 添加测试刻画已有行为 174
8.8 被遗留代码转移注意力 175
8.9 为rlog创建测试替身 175
8.10 测试驱动开发改动 179
8.11 新的场景 181
8.12 寻求更快测试的简要探索 182
8.13 立竿见影的提炼 183
8.14 用成员变量查看状态 186
8.15 用mock查看状态 187
8.16 其他注入技巧 191
8.17 用Mikado方法大规模改动代码 192
8.18 Mikado方法概览 192
8.19 用Mikado移动一个方法 193
8.20 有关Mikado方法的更多思考 202
8.21 这样做值得吗 203
8.22 结束语 203
第9章 测试驱动开发与多线程 204
9.1 开场白 204
9.2 测试驱动开发多线程应用的核心概念 204
9.3 示例程序GeoServer 205
9.4 性能要求 211
9.5 设计异步方案 213
9.6 依然简单的测试驱动 216
9.7 为多线程做好准备 218
9.8 暴露并发性问题 220
9.9 在测试中创建客户端线程 222
9.10 在ThreadPool中创建多个线程 224
9.11 回到GeoServer 226
9.12 结束语 230
第10章 测试驱动开发的其他概念和讨论 231
10.1 开场白 231
10.2 测试驱动开发与性能 231
10.2.1 性能优化测试的策略 232
10.2.2 相关单元级性能测试 233
10.2.3 尝试优化GeoServer代码 234
10.2.4 TestTimer类 235
10.2.5 性能和小函数 236
10.2.6 推荐 237
10.3 单元测试、集成测试和验收测试 238
10.3.1 测试驱动开发如何与验收测试建立联系 239
10.3.2 程序员定义的集成测试 239
10.3.3 测试驱动开发和验收测试驱动开发的重合部分 240
10.4 变换优先级假设 241
10.4.1 了解变换 241
10.4.2 三角法 242
10.4.3 浏览测试列表 243
10.5 编写断言 252
10.5.1 断言—行为—排列 253
10.5.2 示例程序优先,或至少第二 253
10.6 结束语 255
第11章 发展和维持测试驱动开发 256
11.1 开场白 256
11.2 向非技术人员解释测试驱动开发 256
11.2.1 测试驱动什么 257
11.2.2 关于TDD的研究 259
11.3 不良测试的死亡漩涡(亦称为SCUMmy周期) 260
11.4 结对编程 261
11.4.1 结对原则 262
11.4.2 结对编程与测试驱动开发 262
11.4.3 角色切换 263
11.5 Kata和Dojo 264
11.5.1 在测试驱动开发中应用Kata 264
11.5.2 Dojo 265
11.6 有效地使用代码覆盖率统计 266
11.7 持续集成 267
11.8 为团队制定测试驱动开发标准 268
11.9 保持与社区同步 268
11.9.1 阅读测试 268
11.9.2 博客与论坛 269
11.10 结束语 269
附录A 比较单元测试工具 270
附录B 代码Kata:罗马数字转换器 273
附录C 参考文献 282