RSpec 嵌套资源上 PUT 更新操作的控制器测试

RSpec controller tests of PUT update action on nested resource

我正在学习 Rails 以及如何使用 RSpec 进行测试。我需要帮助完成 PUT 更新操作的 RSpec 控制器测试。控制器控制嵌套资源。嵌套路由和相关程序代码在 Web 浏览器中按预期工作。我只需要帮助为 PUT 更新操作编写 RSpec 测试。我已经通过了控制器执行的其他操作的测试。

我知道必须将路径以及父子 ID 传递给 put 方法,但我对以下内容感到困惑:(1) 如何使用 FactoryGirl 对象正确设置 PUT 更新测试,以及(2) 将路径和 ID 传递到 PUT 方法的正确 RSpec 语法。

来自rake路线的相关路线:

  PATCH  /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update
  PUT    /members/:member_id/cardio_exercises/:id(.:format)      cardio_exercises#update

routes.rb 包含: 资源:成员做 资源:cardio_exercises 结束

members.rb 包含: has_many :cardio_exercises, :dependent => :destroy

cardio_exercises.rb 包含: belongs_to:成员

相关工厂:

FactoryGirl.define do
 factory :cardio_exercise do
   title "My cardio exercise"
   duration 30
   calories_burned 300
   date "2014-11-15"       
   association :member     
 end
end


FactoryGirl.define do
  factory :member do
    first_name {Faker::Name.first_name}
    last_name {Faker::Name.last_name}
    age 21
    height 75
    weight 195
    goal "fffff" * 5
    start_date "2014-11-15"     
  end
end

cardio_exercises_controller.rb

class CardioExercisesController < ApplicationController

# :get_member is defined in the private method at the bottom of this file,
# and takes the member_id provided by the routing and
#converts it to a @member object.

before_action :get_member    

# GET member/1/cardio_exercises
# GET member/1/cardio_exercises.json
def index
@cardio_exercises = @member.cardio_exercises
end

# GET member/1/cardio_exercises/1
# GET member/1/cardio_exercises/1.json
def show
 cardio_exercise = @member.cardio_exercises.find(params[:id])
end

# GET member/1/cardio_exercises/new
def new
  @member = Member.find(params[:member_id])
  @cardio_exercise = @member.cardio_exercises.build
end

# GET member/1/cardio_exercises/1/edit
def edit
@cardio_exercise = @member.cardio_exercises.find(params[:id])
end

# POST member/1/cardio_exercises
# POST member/1/cardio_exercises.json
def create
@cardio_exercise = @member.cardio_exercises.build(cardio_exercise_params)

if @cardio_exercise.save
flash[:success] = "Cardio exercise was successfully created."
redirect_to member_cardio_exercises_path(@member)
else
render 'new'
end
end  

# PATCH/PUT member/1/cardio_exercises/1
# PATCH/PUT member/1/cardio_exercises/1.json
def update
 @cardio_exercise = @member.cardio_exercises.find(params[:id])
  if @cardio_exercise.update(cardio_exercise_params)
  flash[:success] = "Cardio exercise was successfully updated."
  redirect_to member_cardio_exercises_path(@member)
else
render 'edit'
end
end

# DELETE member/1/cardio_exercises/1
# DELETE member/1/cardio_exercises/1.json
def destroy
@cardio_exercise = @member.cardio_exercises.find(params[:id])
@cardio_exercise.destroy
respond_to do |format|
format.html { redirect_to (member_cardio_exercises_path(@member)), notice: 'Cardio exercise was    successfully destroyed.' }
format.json { head :no_content }
end
end

private
# The get_member action converts the member_id given by the routing
# into an @member object, for use here and in the view.

def get_member
@member = Member.find(params[:member_id])
end


def cardio_exercise_params
params.require(:cardio_exercise).permit(:title, :duration, :calories_burned, :date, :member_id)
end
end

cardio_exercises_controller_spec.rb 和我尝试设置 PUT 更新操作的几个测试:

require 'rails_helper'

RSpec.describe CardioExercisesController, :type => :controller do
  before :each do
    @member = FactoryGirl.create(:member)      
    @cardio_exercise = FactoryGirl.create(:cardio_exercise, member: @member)      
    @cardio_exercise_attributes = FactoryGirl.attributes_for(:cardio_exercise, :member_id => @member)
    @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title => "Your Cardio Exercise", :member_id => @member)
  end

describe "GET index" do
it "assigns all cardio_exercises as @member.cardio_exercises" do
  get :index, { :member_id => @member  }
  expect(assigns(:cardio_exercises)).to eq(@member.reload.cardio_exercises)
end
end

describe "GET show" do
it "assigns the requested cardio_exercise as @cardio_exercise" do
  get :show, { :member_id => @member, :id => @cardio_exercise }    
  expect(assigns(:cardio_exercise)).to eq(@cardio_exercise)  
end
end 

describe "GET new" do
 it "assigns a new cardio_exercise as @member.cardio_exercise" do
  get :new, { :member_id => @member }
  expect(assigns(:cardio_exercise)).to be_a_new(CardioExercise)
end
end

 describe "GET edit" do
  it "assigns the requested cardio_exercise as @member.cardio_exercise" do      
  get :edit, { :member_id => @member, :id => @cardio_exercise }
  expect(assigns(:cardio_exercise)).to eq(@cardio_exercise) 
 end
end

describe "POST create" do
  describe "with valid params" do
  it "creates a new CardioExercise" do        
    expect {          
      post :create, { :member_id => @member, :cardio_exercise => @cardio_exercise_attributes }
    }.to change(CardioExercise, :count).by(1)         
  end

  it "assigns a newly created cardio_exercise as @cardio_exercise" do
    post :create, { :member_id => @member, :cardio_exercise => @cardio_exercise_attributes }        
    expect(assigns(:cardio_exercise)).to be_a(CardioExercise)
    expect(assigns(:cardio_exercise)).to be_persisted
  end

  it "redirects to the created cardio_exercise" do
    post :create, { :member_id => @member, :cardio_exercise => @cardio_exercise_attributes }
    expect(response).to redirect_to(member_cardio_exercises_path(@member))
  end
  end
 end

 describe "PUT update" do
  describe "with valid params" do

  it "updates the requested cardio_exercise" do
    put :update, { :member_id => @member, :id => @cardio_exercise_update_attributes }
    @member.cardio_exercise.reload                      
    put :update, { :member_id => @member, :id => @cardio_exercise_update_attributes}

  end

  it "assigns the requested cardio_exercise as @member.cardio_exercise" do
    put :update, { :member_id => @member, :cardio_exercise => @cardio_exercise_update_attributes = FactoryGirl.attributes_for(:cardio_exercise, :title => "Your Cardio Exercise", :member_id => @member)}
    expect(assigns(:cardio_exercises)).to eq(@member.cardio_exercises)
  end

  it "redirects to the cardio_exercise" do 
    put :update, { :member_id => @member, :id => @cardio_exercise }        
    expect(response).to redirect_to(@member.cardio_exercise)
  end
 end

 describe "with invalid params" do
  xit "assigns the cardio_exercise as @member.cardio_exercise" do

  end

  xit "re-renders the 'edit' template" do

    expect(response).to render_template("edit")
  end
 end
end

describe "DELETE destroy" do
  it "destroys the requested cardio_exercise" do
  expect {
    delete :destroy, { :member_id => @member, :id => @cardio_exercise }
  }.to change(CardioExercise, :count).by(-1)
  end

  it "redirects to the cardio_exercises list" do      
  delete :destroy, { :member_id => @member, :id => @cardio_exercise }
  expect(response).to redirect_to(member_cardio_exercises_url)
  end
end
end

请查看我的测试设置和 PUT 更新测试。具体来说,我的设置是否是测试 PUT 更新操作的正确方法?

如何更改控制器更新操作的设置 and/or 测试,以便:

(1) 我的测试与更新操作的路由匹配?

(2) 我以正确的 RSpec 语法传递必要的父 ID 和子 ID,以便可以找到记录?

感谢任何帮助!

您必须传递 member_id、cardio_exercise 的 idcardio_exercise 参数才能更新:

put :update, { 
  :member_id => @member, 
  :id => @cardio_exercise.id, 
  :cardio_exercise => @cardio_exercise_update_attributes 
}