花了几个月时间试图修改RSpec / TDD。遇到一些使用嵌套属性测试控制器的挑战。关于如何正确设置并将参数传递给控制器,我有点模糊。我可以构建控制器,使其在浏览器中实际按预期工作 - 我似乎无法对测试进行逆向工程以确认。
感谢任何建议:a)修复下面的测试,b)建议任何更好的方法(例如使用模拟,存根等)。
这是基本的模型结构:
class School < ActiveRecord::Base
has_many :scholarships
end
class Scholarship < ActiveRecord::Base
belongs_to :school
end
我已经按照您的预期配置了routes.rb:
resources :schools do
resources :scholarships, only: [:new, :create, :destroy]
end
在控制器中,#new和#create非常适合Rails应用程序:
class ScholarshipsController < ApplicationController
def new
@school = School.find(params[:school_id])
@scholarship = @school.scholarships.build
end
def create
@school = School.find(params[:school_id])
@scholarship = @school.scholarships.create(scholarship_params)
if @scholarship.save
flash[:success] = 'Scholarship created!'
redirect_to @school
else
render 'new'
end
end
private
def scholarship_params
params.require(:scholarship).permit(:name, ** Lots of params omitted for brevity **,
:notes, school: [:id])
end
end
规范是我似乎无法解决问题的地方。对于spec / controllers / scholarships_controller_spec.rb:
require 'rails_helper'
describe ScholarshipsController, type: :controller do
describe 'POST #create' do
context 'with valid attributes' do
before :each do
@school = create(:school)
@scholarship = @school.scholarships.create(FactoryGirl.build(:scholarship).attributes)
end
it 'receives :save' do
post :create, { scholarship: @scholarship.attributes, school: @school.id }
expect(@scholarship).to receive(:save)
end
end
end
end
当我运行该测试时,我收到以下错误:
Failures:
1) ScholarshipsController POST #create with valid attributes receives :save
Failure/Error: post :create, scholarship: { attributes: @scholarship.attributes, school: @school.id } #school_id: @school.id, scholarship: @scholarship
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"scholarships",
:scholarship=>{"id"=>"1", "name"=>"Dynamic Metrics Director Scholarship", *** Lots of parameters omitted for brevity ***
, "school_id"=>"2"}, :school=>"2"}
这些参数对我来说是正确的。奖学金和学校都有一套属性。但路由不起作用。我已经尝试了十几种不同的方法来尝试让它发挥作用。感到振奋的是,我显然传递了一个(或多或少是正确的)参数哈希,但无法弄清楚我哪里出错了。
******编辑******
根据以下发布的答案进行了更新。 根据Srdjan:
的建议更改了规范的语法 it 'receives :save' do
post :create, "schools/#{@school.id}/scholarships", { scholarship: @scholarship.attributes, school_id: @school.id }
expect(@scholarship).to receive(:save)
end
这会更改错误消息。我假设这表明参数正在正确传递,因为它不再抛出与路由/参数相关的错误..?错误信息是:
1) ScholarshipsController POST #create with valid attributes receives :save
Failure/Error: expect(@scholarship).to receive(:save)
(#<Scholarship:0x007fe293b02598>).save(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
只是为了好的衡量标准,以下是相关路线,我之前没有发布过:
school_scholarships POST /schools/:school_id/scholarships(.:format) scholarships#create
new_school_scholarship GET /schools/:school_id/scholarships/new(.:format) scholarships#new
school_scholarship DELETE /schools/:school_id/scholarships/:id(.:format) scholarships#destroy
答案 0 :(得分:1)
在您的测试中,您将错误地发布到错误的路线。作为routes.rb
中的设置,奖学金资源不存在于学校资源的背景之外。
为了解决这个问题,你必须回答一个问题:&#34;用户是否有必要在不指定学校的情况下访问奖学金记录?&#34;
如果答案是肯定的,您可以复制scholarships
路由并将其粘贴到schools
资源块之外。这样,您既可以获得奖学金,也无需指定学校,也可以指定学校。
如果问题的答案是否定的,那么你需要修理你的测试:
it 'receives :save' do
post :create, "schools/#{@school.id}/scholarhips", { scholarship: @scholarship.attributes, school_id: @school.id }
expect(@scholarship).to receive(:save)
end