使用嵌套资源和相关 FactoryGirl 对象的 Controller 测试失败 RSpec
Failing RSpec tests of Controller with nested resource and associated FactoryGirl objects
我正在构建一个项目来学习 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 => :destroy
cardio_exercises.rb 包含:
belongs_to:成员
Rspec Failures/Errors:
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" = ]
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" = ]
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" = ]
我认为“未找到记录”错误表明会员和有氧运动模型之间的关联存在问题。控制器未通过其 ID 找到有氧运动。我在为 RSpec 进行设置时遗漏了什么?修复设置的最佳方法是什么?
未定义的方法错误似乎是我在 CardioExercise 上调用最后一个方法引起的。我发布到示例中的创建方法。 CardioExercise 是 class。有人可以解释为什么该调用会触发错误,以及如何修复它吗?
感谢任何帮助!
您创建了两个独立的objects/records:成员和cardio_exercise。
您应该将 @member
传递给工厂 cardio_exercise
以连接它们。
@member = FactoryGirl.create(:member)
@cardio_exercise = FactoryGirl.create(:cardio_exercise, member: @member)
PS 当您在没有设置的情况下创建 cardio_exercise
时 member
工厂在 table 成员中创建新记录并分配给 cardio_exercise
这个新记录
更新
关于"GET index"
您创建了 @member
,但没有任何关联 cardio_exercises
。您稍后添加了它们,对象 @member
对此一无所知。您应该重新加载对象以从 DB
获取数据
expect(assigns(:cardio_exercises)).to eq(@member.reload.cardio_exercises)
有时我会将关系转换为数组并对结果进行排序以避免顺序不同时测试失败
我正在构建一个项目来学习 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 => :destroy
cardio_exercises.rb 包含: belongs_to:成员
Rspec Failures/Errors:
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" = ]
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" = ]
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" = ]
我认为“未找到记录”错误表明会员和有氧运动模型之间的关联存在问题。控制器未通过其 ID 找到有氧运动。我在为 RSpec 进行设置时遗漏了什么?修复设置的最佳方法是什么?
未定义的方法错误似乎是我在 CardioExercise 上调用最后一个方法引起的。我发布到示例中的创建方法。 CardioExercise 是 class。有人可以解释为什么该调用会触发错误,以及如何修复它吗?
感谢任何帮助!
您创建了两个独立的objects/records:成员和cardio_exercise。
您应该将 @member
传递给工厂 cardio_exercise
以连接它们。
@member = FactoryGirl.create(:member)
@cardio_exercise = FactoryGirl.create(:cardio_exercise, member: @member)
PS 当您在没有设置的情况下创建 cardio_exercise
时 member
工厂在 table 成员中创建新记录并分配给 cardio_exercise
这个新记录
更新
关于"GET index"
您创建了 @member
,但没有任何关联 cardio_exercises
。您稍后添加了它们,对象 @member
对此一无所知。您应该重新加载对象以从 DB
expect(assigns(:cardio_exercises)).to eq(@member.reload.cardio_exercises)
有时我会将关系转换为数组并对结果进行排序以避免顺序不同时测试失败