使用嵌套资源和关联的FactoryGirl对象对Controller进行RSpec测试失败

时间:2015-02-10 06:36:06

标签: ruby-on-rails testing rspec tdd factory-bot

我正在构建一个学习Rails和测试的项目,并努力解决指向嵌套资源的控制器的RSpec测试中的错误。我的代码在浏览器中按预期工作。我相信这个问题与我的测试设置和FactoryGirl对象的关联有关。我需要帮助排除故障并修复控制器规范。

这是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

require 'rails_helper'

RSpec.describe CardioExercisesController, :type => :controller do
before :each do
  @member = FactoryGirl.create(:member)
  @cardio_exercise = FactoryGirl.create(:cardio_exercise)      
  @cardio_exercise_attributes = FactoryGirl.attributes_for(: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.cardio_exercises)
end
end

describe "GET show" do
it "assigns the requested cardio_exercise as @member.cardio_exercise" do
  get :show, { :member_id => @member, :id => @cardio_exercise }    
  expect(assigns(:cardio_exercise)).to eq(@member.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      

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(CardioExercise.last)
  end  
  end
  end

  describe "PUT update" do
  describe "with invalid params" do

  xit "updates the requested cardio_exercise" do
    #put :update, { id: @member.id, member_id: cardio_exercise: @cardio_exercise.id }
  end

  xit "assigns the requested cardio_exercise as @member.cardio_exercise" do

  end

  xit "redirects to the cardio_exercise" do

  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

这些是相关的工厂:

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

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

members.rb包含:     has_many:cardio_exercises,:dependent =&gt; :破坏

cardio_exercises.rb包含:     belongs_to:member

Rspec失败/错误:

1) CardioExercisesController GET show assigns the requested cardio_exercise as @member.cardio_exercise
 Failure/Error: get :show, { :member_id => @member, :id => @cardio_exercise }
 ActiveRecord::RecordNotFound:
   Couldn't find CardioExercise with 'id'=25 [WHERE "cardio_exercises"."member_id" = $1]

2) CardioExercisesController POST create with valid params redirects to the created cardio_exercise
 Failure/Error: expect(response).to redirect_to(CardioExercise.last)
 NoMethodError:
   undefined method `cardio_exercise_url' for #<CardioExercisesController:0x00000008bba960>

3) CardioExercisesController DELETE destroy destroys the requested cardio_exercise
 Failure/Error: delete :destroy, { :member_id => @member, :id => @cardio_exercise }
 ActiveRecord::RecordNotFound:
   Couldn't find CardioExercise with 'id'=34 [WHERE "cardio_exercises"."member_id" = $1]

4) CardioExercisesController DELETE destroy redirects to the cardio_exercises list
 Failure/Error: delete :destroy, { :member_id => @member, :id => @cardio_exercise }
 ActiveRecord::RecordNotFound:
   Couldn't find CardioExercise with 'id'=35 [WHERE "cardio_exercises"."member_id" = $1]

我认为记录未发现错误表明会员和有氧运动模型之间的关联存在问题。控制器没有通过其身份识别进行有氧运动。在为RSpec设置时我错过了什么?修复设置的最佳方法是什么?

Undefined方法错误似乎是由我在CardioExercise上调用最后一个方法引起的。我正在发布示例中的create方法。 CardioExercise就是这个类。有人可以解释为什么该调用会触发错误,以及如何解决它?

我感谢任何帮助!

1 个答案:

答案 0 :(得分:2)

您可以创建两个独立的对象/记录:member和cardio_exercise。 您应该将@member传递给工厂cardio_exercise以进行连接。

@member = FactoryGirl.create(:member)
@cardio_exercise = FactoryGirl.create(:cardio_exercise, member: @member)  

PS如果在没有设置cardio_exercise的情况下创建member,工厂会在表格成员中创建新记录并为cardio_exercise分配此新记录

<强>更新

关于&#34; GET索引&#34;

您创建的@member没有任何关联的cardio_exercises。您稍后添加了它们,对象@member对此一无所知。您应该重新加载对象以从DB

获取数据
expect(assigns(:cardio_exercises)).to eq(@member.reload.cardio_exercises)

有时我会将关系转换为数组并对结果进行排序,以避免在订单不同时失败测试