I have two classes:
1.Sale is a subclass of ActiveRecord; its job is to persist sales data to the database.
class Sale < ActiveRecord::Base
def self.total_for_duration(start_date, end_date)
self.count(conditions: {date: start_date..end_date})
end
#...
end
2.SalesReport is a standard Ruby class; its job is to produce and graph information about Sales.
class SalesReport
def initialize(start_date, end_date)
@start_date = start_date
@end_date = end_date
end
def sales_in_duration
Sale.total_for_duration(@start_date, @end_date)
end
#...
end
Because I want to use TDD and I want my tests to run really fast, I have written a spec for SalesReport that doesn't doesn't load Rails:
require_relative "../../app/models/sales_report.rb"
class Sale; end
# NOTE I have had to re-define Sale because I don't want to
# require `sale.rb` because it would then require ActiveRecord.
describe SalesReport do
describe "sales_in_duration" do
it "calls Sale.total_for_duration" do
Sale.should_receive(:total_for_duration)
SalesReport.new.sales_in_duration
end
end
end
This test works when I run bundle exec rspec spec/models/report_spec.rb
.
However this test fails when I run bundle exec rake spec
with the error superclass mismatch for class Sale (TypeError)
. I know the error is happening because Tap is defined by sale.rb
and inline within the spec.
So my question is there a way to Stub (or Mock or Double) a class if that class isn't defined? This would allow me to remove the inline class Sale; end
, which feels like a hack.
If not, how do I set up my tests such that they run correctly whether I run bundle exec rspec
or bundle exec rake spec
?
If not, is my approach to writing fast tests wrong?!
Finally, I don't want to use Spork. Thanks!