Rails:如何存根和测试这个外部服务调用?

时间:2014-10-31 09:05:55

标签: ruby-on-rails testing rspec webmock

您好我在rails模型中有类似下面的代码:

class Page < ActiveRecord::Base
  def calculate_page_speed(url)
    browser = Watir::Browser.new :phantomjs
    start = Time.now
    browser.goto url
    finish = Time.now
    self.speed = finish - start
  end
end

以下是测试:

describe Page do
  context "calculate_page_speed for Page" do
    let(:google) { FactoryGirl.create(:page, url: "http://www.google.com") }

    it "should set the page speed" do
      google.speed.should be_nil
      google.calculate_page_speed
      google.speed.should_not be_nil
    end
  end
end

如何有效地存储外部服务,以便在测试期间不调用它?

2 个答案:

答案 0 :(得分:2)

有一种方法:

class Page < ActiveRecord::Base
  def calculate_page_speed(url)
    start = Time.now
    browser.goto url
    finish = Time.now
    self.speed = finish - start
  end

  def browser
    @browser ||= Rails.env.test? ? FakeBrowser.new : Watir.new(:phantomjs)
  end

  class FakeBrowser
    def goto
    end
  end 
end

但是你在prod代码中有测试代码并不是很好。


派生的解决方案是在配置中注入预期的浏览器类。


最后你可以发短信:

Watir::Browser.any_instance.stub(:goto)

答案 1 :(得分:1)

我不认为visiting a url and measuring the speed属于Page模型,设置速度,而不是实际计算。所以我愿意 在lib中创建一个允许我测量网址速度的类,然后使用该类。我会允许该类注入一个存根。

类似这样的事情,在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 

您的Page变为:

def calculate_page_speed(url) 
  self.speed = PageVisitor.new.measure_speed(url)
end

通过该设置,您可以简化测试:在Page中,您必须检查正确的函数,同样,在PageVisitor中检查goto是否被调用,实际上去了页面。

所以,在spec/models/page_spec.rb中写道:

 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 

使用any_instance可能会被视为气味,但在这种情况下,我认为这是测试它的最简单方法。如果你真的想避免它,而不是改变代码(我认为代码没问题,不需要注入PageVisitor imho),你可以存根PageVisitor.new来返回特定的{{1}然后你可以在那个实例上存根PageVisitor

measure_speed

spec/lib/page_visitor_spec.rb

这应该让你开始。