views:

342

answers:

2

Hi All

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 create! 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...

+1  A: 

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.

zetetic
Fantastic, that worked fine. I've been bashing my head with the problem for a couple of hours and solved the other issues but have been a bit blinkered. Many thanks.
emson
A: 

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.

henning-koch