内容简介
本书从最基础的知识入手,讲解了Web开发的全过程,并展示了如何使用Python做测试驱动开发。这本书由三部分组成。第一部分介绍了测试驱动开发和Django的基础知识。第二部分讨论了Web开发的要素,讨论了Web开发过程中不可避免的问题,以及如何通过测试来解决这些问题。第三部分讨论了一些前沿课题,如仿真技术、集成第三方插件、Ajax、测试固件、持续集成等。这本书适合Web开发人员阅读。
目录
- 前言xv
- 准备工作和应具备的知识xxi
- 致谢xxvii
- 第一部分TDD 和Django 基础
- 第1章使用功能测试协助安装Django3
- 1.1遵从测试山羊的教诲,没有测试什么也别做3
- 1.2让Django运行起来6
- 1.3创建Git仓库7
- 第2章使用unittest模块扩展功能测试11
- 2.1使用功能测试驱动开发一个最简可用的应用11
- 2.2Python标准库中的unittest模块14
- 2.3隐式等待16
- 2.4提交16
- 第3章使用单元测试测试简单的首页18
- 3.1第一个Django应用,第一个单元测试19
- 3.2单元测试及其与功能测试的区别19
- 3.3Django中的单元测试20
- 3.4Django中的MVC、URL 和视图函数21
- 3.5终于可以编写一些应用代码了22
- 3.6urls.py24
- 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.1YAGNI74
- 6.2.2REST75
- 6.3使用TDD 实现新设计76
- 6.4逐步迭代,实现新设计78
- 6.5使用Django测试客户端一起测试视图、模板和URL80
- 6.5.1一个新测试类80
- 6.5.2一个新URL81
- 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让表单指向刚添加的新URL88
- 6.7调整模型89
- 6.7.1通过外键实现的关联91
- 6.7.2根据新模型定义调整其他代码92
- 6.8每个列表都应该有自己的URL94
- 6.8.1捕获URL中的参数95
- 6.8.2按照新设计调整new_list视图96
- 6.9还需要一个视图,把待办事项加入现有清单97
- 6.9.1小心霸道的正则表达式98
- 6.9.2最后一个新URL98
- 6.9.3最后一个新视图99
- 6.9.4如何在表单中使用那个URL100
- 6.10使用URL 引入做最后一次重构102
- 第二部分Web开发要素
- 第7章美化网站:布局、样式及其测试方法106
- 7.1如何在功能测试中测试布局和样式106
- 7.2使用CSS框架美化网站109
- 7.3Django模板继承111
- 7.4集成Bootstrap112
- 7.5Django中的静态文件114
- 7.6使用Bootstrap中的组件改进网站外观116
- 7.6.1超大文本块116
- 7.6.2大型输入框116
- 7.6.3样式化表格117
- 7.7使用自己编写的CSS117
- 7.8补遗:collectstatic命令和其他静态目录118
- 7.9没谈到的话题121
- 第8章使用过渡网站测试部署122
- 8.1TDD以及部署的危险区域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安装Nginx128
- 8.4.5解析过渡环境和线上环境所用的域名129
- 8.4.6使用功能测试确认域名可用而且Nginx正在运行130
- 8.5手动部署代码130
- 8.5.1调整数据库的位置131
- 8.5.2创建虚拟环境133
- 8.5.3简单配置Nginx135
- 8.5.4使用迁移创建数据库137
- 8.6为部署到生产环境做好准备138
- 8.6.1换用Gunicorn138
- 8.6.2让Nginx伺服静态文件139
- 8.6.3换用Unix套接字140
- 8.6.4把DEBUG设为False,设置ALLOWED_HOSTS141
- 8.6.5使用Upstart确保引导时启动Gunicorn141
- 8.6.6保存改动:把Gunicorn 添加到requirements.txt142
- 8.7自动化143
- 第9章使用Fabric自动部署147
- 9.1分析一个Fabric部署脚本148
- 9.2试用部署脚本151
- 9.2.1部署到线上服务器153
- 9.2.2使用sed配置Nginx 和Gunicorn155
- 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.3Django怪异的表现:保存时不验证数据166
- 10.3在视图中显示模型验证错误167
- 10.4Django模式:在渲染表单的视图中处理POST 请求171
- 10.4.1重构:把new_item实现的功能移到view_list 中172
- 10.4.2在view_list 视图中执行模型验证174
- 10.5重构:去除硬编码的URL176
- 10.5.1模板标签{% url %}176
- 10.5.2重定向时使用get_absolute_url177
- 第11章简单的表单181
- 11.1把验证逻辑移到表单中181
- 11.1.1使用单元测试探索表单API182
- 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在清单视图中使用ExistingListItemForm209
- 第13章试探JavaScript213
- 13.1从功能测试开始213
- 13.2安装一个基本的JavaScript 测试运行程序214
- 13.3使用jQuery 和<div>固件元素217
- 13.4为想要实现的功能编写JavaScript单元测试219
- 13.5JavaScript测试在TDD循环中的位置221
- 13.6经验做法:onload样板代码和命名空间222
- 13.7一些缺憾223
- 第14章部署新代码224
- 14.1部署到过渡服务器224
- 14.2部署到线上服务器225
- 14.3如果看到数据库错误该怎么办225
- 14.4总结:为这次新发布打上Git 标签225
- 第三部分高级话题
- 第15章用户认证、集成第三方插件以及JavaScript模拟技术的使用228
- 15.1Mozilla Persona(BrowserID)229
- 15.2探索性编程(又名“探究”)229
- 15.2.1为此次探究新建一个分支230
- 15.2.2前端和JavaScript代码230
- 15.2.3Browser-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.7QUnit 中的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.5get_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”页面:由外而内的TDD305
- 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使用模板设计API310
- 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安装Jenkins346
- 20.1.1Jenkins的安全配置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安装node361
- 20.7.2在Jenkins中添加构建步骤362
- 20.8CI 服务器能完成的其他操作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
- 附录APythonAnywhere385
- 附录B基于类的Django 视图388
- 附录C使用Ansible配置服务器398
- 附录D测试数据库迁移402
- 附录E接下来做什么407
- 附录F速查表411
- 附录G参考书目415
- 作者简介416
- 封面介绍416
第一次深入接触测试驱动开发(TDD),准确的说是第一次接触测试。TTD这个理念对我这菜鸟来说很新颖,完全颠覆了以前的观念。但还是觉得先写测试的话,很影响效率。其实最早想读这书,仅仅是为了更好学习Django。。。读了大半,啃不动了,还得再多多补习一下
大致浏览了一遍,TDD的方式国内应该极少有公司采用,所以这才是这本书销量不好的原因。django框架本身的教程并不深入,反而很多内容适合运维和自动化测试的人去学习,内容还算是简单易懂,步骤详细解释清楚算是TDD的入门好书。