在这种情况下如何模拟对象?没有明显的方法用mock替换对象

时间:2011-02-01 23:14:03

标签: ruby-on-rails ruby unit-testing mocking rspec

假设我在Store的模型中有这个非常简单的方法:

  def geocode_address
      loc = Store.geocode(address)
    self.lat = loc.lat
    self.lng = loc.lng
  end

如果我想编写一些不受地理编码服务影响的测试脚本(可能已关闭,有限制或依赖于我的互联网连接),我该如何模拟地理编码服务?如果我可以将地理编码对象传递给方法,那将很容易,但我不知道在这种情况下我怎么做。

谢谢!
特里斯坦

3 个答案:

答案 0 :(得分:8)

使用内置模拟和存根的rspecs,你可以这样做:

setup do
  @subject = MyClass.new
end

it 'handles geocoder success' do
  mock_geo = mock('result', :lat => 1, :lng => 1)

  Store.stub!(:geocode).and_return mock_geo

  @subject.geocode_address

  @subject.lat.should == mock_geo.lat
  @subject.lng.should == mock_geo.lng
end


it 'handles geocoder errors' do
  Store.stub!(:geocode).and_raise Exception

  @subject.geocode_address

  @subject.lat.should == _something_reasonable_
  @subject.lng.should == _something_reasonable_
end

答案 1 :(得分:2)

使用Double-R(RR)https://github.com/btakita/rr,很简单:

test 'should mock the geocoding service' do
  store = Store.new

  mock_location = mock(Object.new)
  mock_location.lat{1.234}
  mock_location.lng{5.678}
  mock(Store).geocode.with_any_args{mock_location}

  store.geocode_address
  assert_equal 1.234, store.lat
  assert_equal 5.678, store.lng
end

答案 2 :(得分:0)

如果无法模拟服务,则表明设计不佳。该服务应与模型分开(无论Store是什么)。您只需要重构为一个更加去耦合的系统,这将允许您模拟它,并使系统更易于维护。