Rails 5 Test Prescriptions 第3章Test-Driven Rails

本章,你将扩大你的模型测试,测试整个Rails栈的逻辑(从请求到回复,使用端到端测试)。

使用Capybara来帮助写end-to-end 测试。 

好的测试风格,包括端到端测试,大量目标明确的单元测试,和相关的一些覆盖中间代码的测试。


开始写Rails

Requirements-gathering,分析需求,是一整本书的内容。本节假设是写一个自用的小程序,因此无需military-grade precision。

列出非正式的需求单子:

  • A user can enter a task, associate it with a project, and also see it on the project page.
  • A user can create a project and seed it with initial tasks using the somewhat contrived syntax of task name:size.
  • A user can change a task’s state to mark it as done.
  • A project can display its progress and status using the date projection you created in the last chapter. 

end to end Test 

新版Rails默认加了Capybara. 

建立目录spec/support/system.rb

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :rack_test
  end
end

同时把rails_helper.rb中注释的语句

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }  激活。

⚠️rack_test :  which is provided by Capybara to simulate a browser DOM tree without JavaScript. (详细见第8章 Integration Testing with Capybara

第一个测试: 一个用户增加一个project. 

  • Given: 开始于空数据,没有步骤
  • When: 填写一个project表格 ,并提交
  • Then: 确认新project显示在projects list,同时附加上entered tasks.

 使用系统测试,就是功能测试把?  spec/system/add_project_spec.rb 

require "rails_helper"
RSpec.describe "adding a project", type: :system do
  it "allows a user to create a project with tasks" do
    visit new_project_path
    fill_in "Name", with:"Project Runway"
    fill_in "Tasks", with:"Choose Fabric:3\nMake it Work:5"
    click_on("Create Project")
    visit projects_path
    expect(page).to have_content("Project Runway")
    expect(page).to have_content 8
  end
end

Pending Tests 

describe , it 如果不带block,就是待定的pending。

也可以加上一个:pending 参数。或放到块内pending "not implemented yet" 

这样系统会提示有pending的案例。 

如过忽略案例,可以在块内加skip,这样案例不会运行。

 

Making the Test Pass

此时运行测试会报错❌,需要使用resource generator。

rails generate resource project name:string due_date:date
rails generate resource task project:references title size:integer completed_at:datetime
⚠️,不要override。手动更新model file 
⚠️使用g resource,不是g scaffold,所以只有空白的controllers和views

Project.rb中移除initialize方法和attr_accessor方法。ActiveRecord接替了这2个功能。

Task.rb同样移除这两个方法,另外把@completed_at改为self.completed_at 

两个模型添加上关联. ⚠️ 让两个类继承ApplicationRecord

然后rake db:migrate

再测试,除了集成测试,之前的都会通过。


The Days Are Action-Packed 

建立controller-new, views/projects/new.html.erb

<%= text_area("project[tasks]")%><br/> 

Going with the workflow 

现在需要做一些决定,你有一些逻辑要处理,当表单提交时,要创建Task实例。这个代码需要前往某个地方,并且单元测试需要指定这个地方是哪。这就是TDD process

有三个位置被经常用于那些响应用户输入超过了普通的传递hash参数到ActiveRecord#create的业务逻辑,见下:

  • 把额外的逻辑放入controller,这是常用的方法。但遇到复杂逻辑则不好使,它会对测试是个麻烦,同时让重构费劲,难以分享,如果在控制器中有多个复杂的动作会让人迷糊。
  • 把额外的逻辑放到关联模型中,常常是至少部分放入class method。容易测试,但重构仍awkward。这种方法也会让模型变得更复杂并且不容易关联跨域多个模型得action
  • 创建一个单独的类来封装这个逻辑和workflow.这是最容易的测试和最好的关联复杂变化的方法。 主要负面是你wind up with a lot of little classes. 作者不介意这个缺点。

Prescription:

Placing business logic outside Rails classes makes that logic easier to test and manage. 

创建一个单独的测试workflows/creates_project_spec.rb

require "rails_helper"
RSpec.describe CreatesProject do
  it "creates a project given a name" do
    creator = CreatesProject.new(name: "Project Runway")
    creator.build
    expect(createor.project.name).to eq "Project Runway"
  end
end
然后编写代码,app/workflows/creates_project.rb
class CreatesProject
  attr_accessor :name, :project
  def initialize(name:"")
    @name = name
  end
  def build
    #不保存
    self.project = Project.new(name:name)
  end
end

测试通过:

猜你喜欢

转载自www.cnblogs.com/chentianwei/p/9085093.html
今日推荐