I do not think that visiting a url and measuring the speed
belongs inside the Page
model, setting the speed is, but not the actual calculation. So I would
create a class in lib
that allows me to measure the speed of a url, and use that class instead. I would allow that class to be injected with a stub.
So something like this, in lib\page_visitor.rb
:
class PageVisitor
def initialize(browser = Watir::Browser.new(:phantomjs))
@browser = browser
end
def measure_speed(url)
start = Time.now
@browser.goto url
finish = Time.now
finish - start
end
end
And the your Page
becomes:
def calculate_page_speed(url)
self.speed = PageVisitor.new.measure_speed(url)
end
So with that setup, you can simplify your tests: in Page
you have to check the right function is called, and likewise, in PageVisitor
check that goto
is called, without actually going to the page.
So, in spec/models/page_spec.rb
write:
let(:google) { FactoryGirl.create(:page, url: "http://www.google.com") }
it("initial speed is zero") { google.speed.should be_nil }
describe `calculating the speed` do
before do
PageVisitor.any_instance.should_receive(:measure_speed).and_return(25)
google.calculate_page_speed
end
it "sets the speed correctly"
google.speed.should == 25
end
end
Using any_instance
could be considered a smell, but in this case I think it is the easiest way to test it. If you really want to avoid it, instead of changing the code (I think the code is ok, no need to inject a PageVisitor
imho), you could stub PageVisitor.new
to return a specific PageVisitor
, and then you can just stub measure_speed
on that instance.
In your spec/lib/page_visitor_spec.rb
write
describe PageVisitor
class FakeBrowser
def goto(url)
sleep 1
end
end
let(:page_visitor) { PageVisitor.new(FakeBrowser.new) }
it "measure the speed" do
page_visitor.measure_speed.should_not be_nil
end
end
This should get you started.