99miles
99miles

Reputation: 11212

Testing has_many association with RSpec

I'm trying to test the Hour model with RSpec, namely the class method 'find_days_with_no_hours' that behaves like a scope. Business has_many Hours associated through STI. find_days_with_no_hours needs to be called through a Business object and I can't figure out how to set this up in the RSpec test. I want to be able to test something like:

bh = @business.hours.find_days_with_no_hours
bh.length.should == 2

I've tried various approaches, like creating a Business object (with, say, Business.create), then setting @business.hours << mock_model(BusinessHour, ..., ..., ...) but that doesn't work.

How is this normally done?

class Business < ActiveRecord::Base

  has_many :hours, :as => :hourable

end

class Hour < ActiveRecord::Base

  belongs_to :hourable, :polymorphic => true

  def self.find_days_with_no_hours
    where("start_time IS NULL")
  end

end

Upvotes: 3

Views: 2445

Answers (1)

nzifnab
nzifnab

Reputation: 16092

You can't test an arel method by creating the object via mocks. Arel is going to go straight into the database, and not see any mocks or anything that you've created in memory. I would grab factory_girl and then define an hour factory for yourself:

Factory.define :hour do |f|
  f.start_time {Time.now}
end

Factory.define :unstarted_day, :parent => :hour do |f|
  f.start_time nil
end

And then in your test...

business = Factory.create(:business)
business.hours << Factory.create(:unstarted_day)

bh = business.hours.find_days_with_no_hours
bh.length.should == 1

However, factory_girl is just a personal preference for setting up known state, you can just as easily use create statements or fixtures, the problem for you was trying to use mock_model() (which prevents a database hit), and then using a method that queries the database.

Upvotes: 8

Related Questions