RSpec mocking a nested model in Rails - ActionController problem
I am having a problem in RSpec when my mock object is asked for a URL by the ActionController. The URL is a Mock one and not a correct resource URL.
I am running RSpec 1.3.0 and Rails 2.3.5
Basically I have two models. Where a subject has many notes.
class Subject < ActiveRecord::Base
validates_presence_of :title
has_many :notes
end
class Note < ActiveRecord::Base
validates_presence_of :title
belongs_to :subject
end
My routes.rb file nests these two resources as such:
ActionController::Routing::Routes.draw do |map|
map.resources :subjects, :has_many => :notes
end
The NotesController.rb file looks like this:
class NotesController < ApplicationController
# POST /notes
# POST /notes.xml
def create
@subject = Subject.find(params[:subject_id])
@note = @subject.notes.create!(params[:note])
respond_to do |format|
format.html { redirect_to(@subject) }
end
end
end
Finally this is my RSpec spec which should simply post my mocked objects to the NotesController and be executed... which it does:
it "should create note and redirect to subject without javascript" do
# usual rails controller test setup here
subject = mock(Subject)
Subject.stub(:find).and_return(subject)
notes_proxy = mock('association proxy', { "create!" => Note.new })
subject.stub(:notes).and_return(notes_proxy)
post :create, :subject_id => subject, :note => { :title => 'note title', :body => 'note body' }
end
The problem is that when the RSpec post method is called.
The NotesController correctly handles the Mock Subject object, and cre开发者_如何学Cate! the new Note object. However when the NoteController#Create method tries to redirect_to I get the following error:
NoMethodError in 'NotesController should create note and redirect to subject without javascript' undefined method `spec_mocks_mock_url' for #<NotesController:0x1034495b8>
Now this is caused by a bit of Rails trickery that passes an ActiveRecord object (@subject, in our case, which isn't ActiveRecord but a Mock object), eventually to url_for who passes all the options to the Rails' Routing, which then determines the URL.
My question is how can I mock Subject so that the correct options are passed so that I my test passes.
I've tried passing in :controller => 'subjects' options but no joy.
Is there some other way of doing this?
Thanks...
Have a look at mock_model
, which is added by rspec-rails to make it easier to mock ActiveRecord objects. According to the api docs:
mock_model: Creates a mock object instance for a model_class with common methods stubbed out.
I'm not sure if it takes care of url_for
, but it's worth a try.
Update, 2018-06-05:
As of rspec 3:
mock_model
andstub_model
have been extracted into the rspec-activemodel-mocks gem.
In case zetetic's idea doesn't work out, you can always say Subject.new
and then stub out to_param
and whatever else you might need faked for your example.
精彩评论