1

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

如何在测试期间有效地存根外部服务而不调用它?

4

2 回答 2

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

但是在这里你在产品代码中有测试代码,这不是很好。


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


最后你可以存根东西:

Watir::Browser.any_instance.stub(:goto)
于 2014-10-31T09:45:56.893 回答
1

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

所以像这样的东西,在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恕我直言),你可以存根PageVisitor.new返回一个特定PageVisitor的,然后你可以只存根measure_speed那个实例。

在你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

这应该让你开始。

于 2014-10-31T11:08:33.037 回答