使用嵌套属性在RSpec中测试POST #create - 无法获得params hash correct

时间:2015-07-26 16:19:54

标签: ruby-on-rails rspec controller params

花了几个月时间试图修改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

1 个答案:

答案 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