总文档链接: git
RSpec.info/documentation/ 编程
如何使用TDD 和 自动化测试来创建一个Rails app。缓存
TDD让你用测试来探索代码的设计。你将学习可利用的工具,并学习用什么工具最好使。Tools comes and tools go, 工具是不断进化的,因此做者但愿读者用最少的步骤写出更好的代码。安全
to help you write great app that do cool things and still catch the train home!ruby
What's in this book?app
开始介绍TDD,它为何起做用,什么时候用TDD。less
而后2章将使用RSpec来为新的Rails app 建立test.ide
以后几章节将单元测试基础,关于models, 多种方法生成测试数据,使用test doubles(替身) to simulate objects and specify hard-to-reach states.工具
而后end-to-end tests 集成测试和Capybara.单元测试
讨论JavaScript 先学习有JS 代码的end-to-end tests,而后学习JS单元测试。
而后,旅行到其余Rails部分,展现系统支持的工具。
12章还会了解使用Minitest来代替RSpec.
13-14章关于指定的场景测试,包括安全测试,测试第三方services.
15章 Debugging and Troubleshooting failing test.⚠️陌生
16章 关键写快速的代码和快速的写代码
17章 Legacy code 遗产代码,从他人那里继承的代码,等同于bad code.
What You'll Need
最新的Ruby2.5和Rails5.2,RSpec 3.7.1, Minitest 5.11.3
做者说RSpec学习曲线稍微陡峭,但这是业界使用最多的工具。Minitest 学习起来比较容易。
也就是常常说的: sometimes the best practice for learning isn't the best practice for experts.
本书版本的更新:
第一章 一个预言故事
不写测试的问题是,重构的时候还要手动测试,而写自动化测试几行不花费额外的时间。
写自动化测试能够防止你忘记测试的步骤。
if you do testing well, your work will go faster。
TDD能够减小bug而且容易改正bug。
TDD步骤:
当你不知道程序须要作什么的时候,TDD没有什么用。由于若是你不指定用什么断言/指望,就无法写测试。 好比view-testing:这时须要先写一部分代码而后立刻测试,灵活一点,做者称为:test-next mode。
在写测试前,先列出一个测试清单,注明你要测试的内容,以防忘记。
在rails 社区,仍有讨论TDD 破坏代码的问题。
做者认为TDD开发不能取代好的设计天赋,TDD仍可能创造bad code。
第2章Test-driven development Basics
Prescription3:(药方->决策)
Initializing objects is a good starting place for a TDD process. Another good approach is to use the test to design what you want a successful interaction of the feature to look like.
下面跟着案例章节走。只记录重点。
Install RSpec
git init, #创建版本控制系统。
mkdir gatherer -> cd gatherer
rails new . -> bundle install
rake db:create:all -> rake db:migrate
而后,安装gem 'rspec-rails' ->再次bundle install
rails generate rspec:install #生成初始化文件
⚠️在.rspec, 加上--format documentation
rails spec #测试是否安装成功。
Where to Start?
初始化对象是 TDD驱动测试开发的好的开始。另外一个好方法是使用test来设计一个看起来成功的交互的功能。
创建spec/models/project_spec.rb,而后创建一个project的初始状态:
注解:
done?是自定义的方法, be_truthy是内建匹配器,判断actual_value是不是真,不是nil或false。
这是结构:expect(actual_value).to matcher
expect是RSpec定义的方法,接收任意object做为参数并return一个特殊的RSpec对象,这个对象被称为 ExpectationTarget.
而后这ExpectationTarget将做为matcher方法的参数,最后返回结果。
Running the test
使用rspec, 全部目录的文件都会被加载。
每一个RSpec文件须要rails_helper文件加载Rails环境,和spec_helper.rb,这里包含非Rails的步骤。
rails_helper.rb会创建固件或预置件。
每一个顶级call to RSpec.describe建立一个内部RSpec对象叫作 example group.
example group使用块参数让describe方法被执行。describe方法里面也能够内嵌example groups。
每一个descirbe方法内可能包含it方法,每一个it方法创造一个独立测试,这个测试叫作example。
在每一个example group中先运行before(:all) 在全部案例运行结束后,运行after(:all)
每一个案例也有before(:example), after(:example) 钩子方法。
Making the Test Pass
运行rspec会报错, uninitialized constant Project,固然了我没创建这个类。
而后有3个不一样的解决办法:
做者的态度,偏重purer。做者的经历,有时候由于过于实际了,致使问题没有理解和忽略了本该测试的步骤。
app/models/project.rb
class Project
end
而后再$rspec , ->undefined method `done?' for <Project:0x00007ff65db9b9b8>
定义done?方法,再测试->expected: truthy value got: nil
测试经过!
The Second Test(只记录重点。)
创建了Task.Project and Task都没有继承ActiveRecord。做者的目的是一步步来。
let
使用let重构。 let(:project) {Project.new}
let方法是一个语法糖。定义一个方法,调用这个方法会缓存这个结果。相似:
不调用就不存在。
let! 则是在定义let方法后,就始终存在:project变量
be_comlete匹配器,是自定义的。
若是没有定义方法 complete?,测试会报错:
expected #<Task:0x00007fe3ac637da0 @completed=false> to respond to `complete?`
知识点:
Adding Some Math
做者在写测试前会想这个测试须要什么,典型的测试结构🈶️3部分:
Prescription:
选择你的测试数据,定义易于理解不重复的测试变量名字, 一旦发送错误,就容易诊断。
知识点:
end
task1 = Task.new(size:1, completed: true)
存储的 task1.@size 是1,
初始化参数是options= {size:1, completed: true}
因此@size = options[:size] = 1
The First Date
目的:把未完成的task和完成的task做个区分的同时,根据完成时间,体现出是近期完成(21天内),仍是非近期完成。
根据测试数据的思考设计3步骤:
增长2个案例:
修改代码:
⚠️a boundary-condition test :数据的设置体如今边界线及其两边。把Task表的completed属性类型从boolean改成date,名字改成completed_at
修改task.rb,增长1个方法。part_of_velocity
知识: Float#nan?
若是是一个不可验证的浮点数则返回NaN, 这个nan?方法是验证是不是nan
a = 0.0/0.0 #=> NaN a.nan? #=> true
知识:
对应可能会发生变更的数字,这个数字用到了多个不一样类的实例方法中,可使用类方法,而不是常量储存preserve这个数字。
之后改动就方便了。
What You've Done
Write a simple test, write simple code to make it pass, and refactor.
TDD 的做用
当你开始作一个需求,而把这个需求转变为逻辑程序,你不能当即就弄清楚这个转变。
使用TDD你能够逐步的攻克这个问题。从小处,利于理解的角落开始,增长了对需求问题的理解后再开始较难的部分。