Unable to stub a class method in a before_filter


#1

Here is my spec:

describe Admin::ProductsController, “A visitor wants to access
admin/products” do

before(:each) do
@product = mock_model(Product, :traffic_available => 0)
Product.stub!(:find_by_domain_name).and_return(@product)
end

it “should redirect to login path” do
get :index
response.should redirect_to(login_url)
end

end

In my application.rb, I have the following before filter:

def find_current_site
@site = Site.find_by_domain_name(website_name)
if @site.traffic_available < 0
render :nothing => :true
end
end

As the test DB is empty and I don’t use fixtures, it won’t find any
site, therefore nil.traffic_available < 0 returns an error when running
the spec.

I thought I could stub out the find_by_domain_name method to return a
cooperative object with a traffic_available value, but it didn’t work.

How can I do that correctly?

I have found a dirty workaround:
controller.stub!(:find_current_site).and_return(:true)

but I don’t find it acceptable. I am not going to stub out all methods
in my app, that’s nonsense.


#2

On Tue, Nov 4, 2008 at 1:38 PM, Fernando P. removed_email_address@domain.invalid
wrote:

it “should redirect to login path” do
@site = Site.find_by_domain_name(website_name)
I thought I could stub out the find_by_domain_name method to return a
cooperative object with a traffic_available value, but it didn’t work.

How can I do that correctly?

I have found a dirty workaround:
controller.stub!(:find_current_site).and_return(:true)

but I don’t find it acceptable. I am not going to stub out all methods
in my app, that’s nonsense.

I don’t know if this will satisfy you or not, but you could write
that once and have it apply across your entire suite. Add this to
spec/spec_helper.rb (or equivalent):

Spec::Runner.configure do |config|
config.before(:each, :type => :controller) do
controller.stub!(:find_current_site).and_return(:true)
end
end

That work?


#3

On 4 Nov 2008, at 19:38, Fernando P. wrote:

Here is my spec:

describe Admin::ProductsController, “A visitor wants to access
admin/products” do

before(:each) do
@product = mock_model(Product, :traffic_available => 0)
Product.stub!(:find_by_domain_name).and_return(@product)

Should this be Site.stub!(:find_by_domain_name)… ?


#4

That work?

It could. But in such case, how will I test my before_filter
independently?

My real problem is to stub the find_by_domain_name instance method.


#5

Are the docs on mock outdated? I sometimes see mock_model, and sometimes
mock. Which one should be used?


#6

Crap! I was stubbing Product, instead of Site! It all works now. Matt’s
typo put me on the track!

But I will definitely use the trick Spec::Runner.configure do
|config|…
to avoid having to type this stub in all my files.

Thanks.


#7

On 4 Nov 2008, at 20:46, Fernando P. wrote:

Are the docs on mock outdated? I sometimes see mock_model, and
sometimes
mock. Which one should be used?

For mock_model, you need to look at the rspec-rails gem, which is a
separate library.

You actually have three choices when mocking an ActiveRecord model:
mock, mock_model and stub_model. mock() belongs to rspec’s core
library, while the latter two come with the rails-specific extension
gem.

See here for the documentation on the two rails mocking methods:
http://rspec.rubyforge.org/rspec-rails/1.1.11/classes/Spec/Rails/Mocks.html#M000026

There’s also a good blog post on David’s blog about stub_model
http://blog.davidchelimsky.net/2008/5/27/rspec-1-1-4

HTH,
Matt


#8

On Nov 4, 2008, at 3:46 PM, Fernando P. wrote:

Are the docs on mock outdated? I sometimes see mock_model, and
sometimes
mock. Which one should be used?

mock_model is for ActiveRecord objects. it’s just a mock() call with
a random id stub set, and a :new_record? => false

Scott


#9

Ok I get it. I was wondering why mock_model was not showing up in
rspec’s rdoc. Thanks for the clarification.