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



你好,我在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

我如何才能有效地存根外部服务,因为它在测试期间没有调用它?

有一种方法类似于:

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)

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

所以类似这样的东西,在libpage_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.new以返回特定的PageVisitor,然后在该实例上存根measure_speed,而不是更改代码(我认为代码还可以,不需要注入PageVisitor imho)。

在您的spec/lib/page_visitor_spec.rb中写入

 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

这应该会让你开始。

相关内容

  • 没有找到相关文章

最新更新