第一部分 TDD和Django基础 3
第1章 使用功能测试协助安装Django 3
1.1遵从测试山羊的教诲,没有测试什么也别做 3
1.2让Django运行起来 6
1.3创建Git仓库 7
第2章 使用unittest模块扩展功能测试 11
2.1使用功能测试驱动开发一个最简可用的应用 11
2.2 Python标准库中的unittest模块 14
2.3隐式等待 16
2.4提交 16
第3章 使用单元测试测试简单的首页 18
3.1第一个Django应用,第一个单元测试 19
3.2单元测试及其与功能测试的区别 19
3.3 Django中的单元测试 20
3.4 Django中的MVC、URL和视图函数 21
3.5终于可以编写一些应用代码了 22
3.6 urls.py 24
3.7为视图编写单元测试 27
第4章 编写这些测试有什么用 31
4.1编程就像从井里打水 31
4.2使用Selenium测试用户交互 33
4.3遵守“不测试常量”规则,使用模板解决这个问题 35
4.4关于重构 39
4.5接着修改首页 40
4.6总结:TDD流程 42
第5章 保存用户输入 45
5.1编写表单,发送POST请求 45
5.2在服务器中处理POST请求 48
5.3把Python变量传入模板中渲染 49
5.4事不过三,三则重构 53
5.5Django ORM和第一个模型 54
5.5.1第一个数据库迁移 56
5.5.2测试向前走得挺远 57
5.5.3添加新字段就要创建新迁移 57
5.6把POST请求中的数据存入数据库 58
5.7处理完POST请求后重定向 61
5.8在模板中渲染待办事项 63
5.9使用迁移创建生产数据库 65
第6章 完成最简可用的网站 70
6.1确保功能测试之间相互隔离 70
6.2必要时做少量的设计 74
6.2.1 YAGNI 74
6.2.2 REST 75
6.3使用TDD实现新设计 76
6.4逐步迭代,实现新设计 78
6.5使用Django测试客户端一起测试视图、模板和URL 80
6.5.1一个新测试类 80
6.5.2一个新URL 81
6.5.3一个新视图函数 81
6.5.4一个新模板,用于查看清单 82
6.6用于添加待办事项的URL和视图 85
6.6.1用来测试新建清单的测试类 85
6.6.2用于新建清单的URL和视图 86
6.6.3删除当前多余的代码和测试 88
6.6.4让表单指向刚添加的新URL 88
6.7调整模型 89
6.7.1通过外键实现的关联 91
6.7.2根据新模型定义调整其他代码 92
6.8每个列表都应该有自己的URL 94
6.8.1捕获URL中的参数 95
6.8.2按照新设计调整new_list视图 96
6.9还需要一个视图,把待办事项加入现有清单 97
6.9.1小心霸道的正则表达式 98
6.9.2最后一个新URL 98
6.9.3最后一个新视图 99
6.9.4如何在表单中使用那个URL 100
6.10使用URL引入做最后一次重构 102
第二部分 Web开发要素 106
第7章 美化网站:布局、样式及其测试方法 106
7.1如何在功能测试中测试布局和样式 106
7.2使用CSS框架美化网站 109
7.3 Django模板继承 111
7.4集成Bootstrap 112
7.5 Django中的静态文件 114
7.6使用Bootstrap中的组件改进网站外观 116
7.6.1超大文本块 116
7.6.2大型输入框 116
7.6.3样式化表格 117
7.7使用自己编写的CSS 117
7.8补遗:collectstatic命令和其他静态目录 118
7.9没谈到的话题 121
第8章 使用过渡网站测试部署 122
8.1 TDD以及部署的危险区域 123
8.2一如既往,先写测试 124
8.3注册域名 126
8.4手动配置托管网站的服务器 126
8.4.1选择在哪里托管网站 127
8.4.2搭建服务器 127
8.4.3用户账户、SSH和权限 128
8.4.4安装Nginx 128
8.4.5解析过渡环境和线上环境所用的域名 129
8.4.6使用功能测试确认域名可用而且Nginx正在运行 130
8.5手动部署代码 130
8.5.1调整数据库的位置 131
8.5.2创建虚拟环境 133
8.5.3简单配置Nginx 135
8.5.4使用迁移创建数据库 137
8.6为部署到生产环境做好准备 138
8.6.1换用Gunicorn 138
8.6.2让Nginx伺服静态文件 139
8.6.3换用Unix套接字 140
8.6.4把DEBUG设为False,设置ALLOWED_HOSTS 141
8.6.5使用Upstart确保引导时启动Gunicorn 141
8.6.6保存改动:把Gunicorn添加到requirements.txt 142
8.7自动化 143
第9章 使用Fabric自动部署 147
9.1分析一个Fabric部署脚本 148
9.2试用部署脚本 151
9.2.1部署到线上服务器 153
9.2.2使用sed配置Nginx和Gunicorn 155
9.3使用Git标签标注发布状态 155
9.4延伸阅读 156
第10章 输入验证和测试的组织方式 158
10.1针对验证的功能测试:避免提交空待办事项 158
10.1.1跳过测试 159
10.1.2把功能测试分拆到多个文件中 160
10.1.3运行单个测试文件 162
10.1.4填充功能测试 163
10.2使用模型层验证 164
10.2.1重构单元测试,分拆成多个文件 164
10.2.2模型验证的单元测试和self.assertRaises上下文管理器 165
10.2.3 Django怪异的表现:保存时不验证数据 166
10.3在视图中显示模型验证错误 167
10.4 Django模式:在渲染表单的视图中处理POST请求 171
10.4.1重构:把new_item实现的功能移到view_list中 172
10.4.2在view_list视图中执行模型验证 174
10.5重构:去除硬编码的URL 176
10.5.1模板标签{url%} 176
10.5.2重定向时使用get_absolute_url 177
第11章 简单的表单 181
11.1把验证逻辑移到表单中 181
11.1.1使用单元测试探索表单API 182
11.1.2换用Django中的ModelForm类 183
11.1.3测试和定制表单验证 184
11.2在视图中使用这个表单 186
11.2.1在处理GET请求的视图中使用这个表单 187
11.2.2大量查找和替换 189
11.3在处理POST请求的视图中使用这个表单 191
11.3.1修改new_list视图的单元测试 191
11.3.2在视图中使用这个表单 192
11.3.3使用这个表单在模板中显示错误消息 193
11.4在其他视图中使用这个表单 194
11.5使用表单自带的save方法 196
第12章 高级表单 199
12.1针对重复待办事项的功能测试 199
12.1.1在模型层禁止重复 200
12.1.2题外话:查询集合排序和字符串表示形式 202
12.1.3重写旧模型测试 204
12.1.4保存时确实会显示完整性错误 205
12.2在视图层试验待办事项重复验证 206
12.3处理唯一性验证的复杂表单 207
12.4在清单视图中使用ExistingListItemForm 209
第13章 试探JavaScript 213
13.1从功能测试开始 213
13.2安装一个基本的JavaScript测试运行程序 214
13.3使用jQuery和<div>固件元素 217
13.4为想要实现的功能编写JavaScript单元测试 219
13.5 JavaScript测试在TDD循环中的位置 221
13.6经验做法:onload样板代码和命名空间 222
13.7一些缺憾 223
第14章 部署新代码 224
14.1部署到过渡服务器 224
14.2部署到线上服务器 225
14.3如果看到数据库错误该怎么办 225
14.4总结:为这次新发布打上Git标签 225
第三部分 高级话题 228
第15章 用户认证、集成第三方插件以及JavaScript模拟技术的使用 228
15.1 Mozilla Persona(BrowserID) 229
15.2探索性编程(又名“探究”) 229
15.2.1为此次探究新建一个分支 230
15.2.2前端和JavaScript代码 230
15.2.3 Browser-ID协议 231
15.2.4服务器端:自定义认证机制 232
15.3去掉探究代码 237
15.3.1常用Selenium技术:显式等待 240
15.3.2删除探究代码 241
15.4涉及外部组件的JavaScript单元测试:首次使用模拟技术 242
15.4.1整理:全站共用的静态文件夹 242
15.4.2什么是模拟技术,为什么要模拟,模拟什么 244
15.4.3命名空间 244
15.4.4在initialize函数的单元测试中使用一个简单的驭件 245
15.4.5高级模拟技术 250
15.4.6检查参数的调用 253
15.4.7 QUnit中的setup和teardown函数,以及Ajax请求测试 255
15.4.8深层嵌套回调函数和测试异步代码 259
第16章 服务器端认证,在Python中使用模拟技术 262
16.1探究登录视图 262
16.2在Python代码中使用模拟技术 263
16.2.1通过模拟authenticate函数测试视图 263
16.2.2确认视图确实登录了用户 266
16.3模拟网络请求,去除自定义认证后台中的探究代码 270
16.3.1一个if语句需要一个测试 270
16.3.2在类上使用patch修饰器 272
16.3.3进行布尔值比较时要留意驭件 275
16.3.4需要时创建用户 276
16.3.5 get_user方法 277
16.4一个最简单的自定义用户模型 279
16.4.1稍微有点儿失望 280
16.4.2把测试当作文档 281
16.4.3用户已经通过认证 282
16.5关键时刻:功能测试能通过吗 283
16.6完善功能测试,测试退出功能 284
第17章 测试固件、日志和服务器端调试 287
17.1事先创建好会话,跳过登录过程 287
17.2实践是检验真理的唯一标准:在过渡服务器中捕获最后的问题 290
17.2.1设置日志 291
17.2.2修正Persona引起的这个问题 293
17.3在过渡服务器中管理测试数据库 295
17.3.1创建会话的Django管理命令 295
17.3.2让功能测试在服务器上运行管理命令 296
17.3.3使用subprocess模块完成额外的工作 298
17.4集成日志相关的代码 301
17.5小结 304
第18章 完成“My Lists”页面:由外而内的TDD 305
18.1对立技术:“由内而外” 305
18.2为什么选择使用“由外而内” 306
18.3 “My Lists”页面的功能测试 306
18.4外层:表现层和模板 307
18.5下移一层到视图函数(控制器) 308
18.6使用由外而内技术,再让一个测试通过 309
18.6.1快速重组模板的继承层级 309
18.6.2使用模板设计API 310
18.6.3移到下一层:视图向模板中传入什么 311
18.7视图层的下一个需求:新建清单时应该记录属主 312
18.8下移到模型层 313
第19章 测试隔离和“倾听测试的心声” 318
19.1重温抉择时刻:视图层依赖于尚未编写的模型代码 318
19.2首先尝试使用驭件实现隔离 319
19.3倾听测试的心声:丑陋的测试表明需要重构 322
19.4以完全隔离的方式重写视图测试 323
19.4.1为了新测试的健全性,保留之前的整合测试组件 323
19.4.2完全隔离的新测试组件 324
19.4.3站在协作者的角度思考问题 324
19.5下移到表单层 328
19.6下移到模型层 332
19.7关键时刻,以及使用模拟技术的风险 335
19.8把层与层之间的交互当作“合约” 336
19.8.1找出隐形合约 337
19.8.2修正由于疏忽导致的问题 338
19.9还缺一个测试 340
19.10清理:保留哪些整合测试 340
19.10.1删除表单层多余的代码 340
19.10.2删除以前实现的视图 341
19.10.3删除视图层多余的代码 342
19.11总结:什么时候编写隔离测试,什么时候编写整合测试 343
19.11.1以复杂度为准则 344
19.11.2两种测试都要写吗 344
19.11.3继续前行 345
第20章 持续集成 346
20.1安装Jenkins 346
20.1.1 Jenkins的安全配置 348
20.1.2添加需要的插件 348
20.2设置项目 350
20.3第一次构建 351
20.4设置虚拟显示器,让功能测试能在无界面的环境中运行 353
20.5截图 355
20.6一个常见的Selenium问题:条件竞争 358
20.7使用PhantomJS运行QUnit JavaScript测试 361
20.7.1安装node 361
20.7.2在Jenkins中添加构建步骤 362
20.8 CI服务器能完成的其他操作 364
第21章 简单的社会化功能、页面模式,以及练习 365
21.1有多个用户以及使用addCleanup的功能测试 365
21.2实现Selenium交互等待模式 367
21.3页面模式 368
21.4扩展功能测试测试第二个用户和“My Lists”页面 371
21.5留给读者的练习 373
第22章 测试运行速度的快慢和炽热的岩浆 375
22.1正题:单元测试除了运行速度超快之外还有其他优势 376
22.1.1测试运行得越快,开发速度越快 376
22.1.2神赐的心流状态 377
22.1.3速度慢的测试经常不想运行,导致代码变坏 377
22.1.4现在还行,不过随着时间推移,整合测试会变得越来越慢 377
22.1.5别只听我一个人说 377
22.1.6单元测试能驱使我们实现好的设计 377
22.2纯粹的单元测试有什么问题 378
22.2.1隔离的测试难读也难写 378
22.2.2隔离测试不会自动测试集成情况 378
22.2.3单元测试几乎不能捕获意料之外的问题 378
22.2.4使用驭件的测试可能和实现方式联系紧密 378
22.2.5这些问题都可以解决 379
22.3合题:我们到底想从测试中得到什么 379
22.3.1正确性 379
22.3.2简洁可维护的代码 379
22.3.3高效的工作流程 379
22.3.4根据所需的优势评估测试 379
22.4架构方案 380
22.4.1端口和适配器(或六边形、简洁)架构 380
22.4.2函数式核心,命令式外壳 381
22.5小结 381
遵从测试山羊的教诲 383
附录A PythonAnywhere 385
附录B 基于类的Django视图 388
附录C 使用Ansible配置服务器 398
附录D 测试数据库迁移 402
附录E 接下来做什么 407
附录F 速查表 411
附录G 参考书目 415
作者简介 416
封面介绍 416