如何在我的应用程序的单元测试中存根flickraw库?

时间:2010-08-21 23:36:34

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

My Rails 2应用程序通过flickraw库显示来自Flickr的照片幻灯片。我的代码有效,但我仍然坚持如何正确编写RSpec单元测试。

我有一个Slide类,它通过flickraw封装了我的应用程序所需的所有内容。它有点像模型对象,但不使用ActiveRecord。它没有做太多工作;它将大部分繁重的工作委托给了flickraw。

我还没有完成测试,因为现在,他们要求我对Flickr中的一些照片ID进行硬编码,如果我重新安排我的照片集或添加新照片,测试就会中断。

所以我所谓的单元测试更像是集成测试。我理解如何使用RSpec编写模拟或存根,但不知道如何使用flickraw库。 如何删除flickraw并将其转换为单元测试?

slide.rb:

require 'flickraw'
FlickRaw.api_key = "xxx"
FlickRaw.shared_secret = "yyy"
flickr.auth.checkToken :auth_token => "zzz"
PHOTOSET_ID = 123123123

class Slide
  attr_accessor :id, :previous_id, :next_id, :url_square, :url_thumbnail, :url_small, :url_medium500,
                :url_medium640, :url_large, :url_original

  def self.last
    photoset = flickr.photosets.getPhotos(:photoset_id => PHOTOSET_ID)
    Slide.new(photoset.photo.last.id)
  end

  def self.first
    photoset = flickr.photosets.getPhotos(:photoset_id => PHOTOSET_ID)
    Slide.new(photoset.photo.first.id)
  end

  def self.find(id)
    Slide.new(id)
  end

  def initialize(id)
    self.id = id
    photo = flickr.photos.getInfo(:photo_id => id)
    context = flickr.photosets.getContext(:photoset_id => PHOTOSET_ID, :photo_id => id)
    sizes = flickr.photos.getSizes(:photo_id => id)

    self.previous_id = (context.prevphoto.id == 0) ? nil : context.prevphoto.id
    self.next_id = (context.nextphoto.id == 0) ? nil : context.nextphoto.id

    sizes.each do |size|
      if size.label == "Square"
        self.url_square = size.source
      elsif size.label == "Thumbnail"
        self.url_thumbnail = size.source
      elsif size.label == "Small"
        self.url_small = size.source
      elsif size.label == "Medium"
        self.url_medium500 = size.source
      elsif size.label == "Medium 640"
        self.url_medium640 = size.source
      elsif size.label == "Large"
        self.url_large = size.source
      elsif size.label == "Original"
        self.url_original = size.source
      end
    end
  end
end

slide_spec.rb:

require 'spec_helper'

describe Slide do
  before(:each) do
    first_photo_id = "444555666"
    @slide = Slide.new(first_photo_id)
  end

  describe "urls" do
    it "should generate the thumbnail url" do
      @slide.url_thumbnail.should match(/_t.jpg$/)
    end

    it "should generate the small url" do
      @slide.url_small.should match(/_m.jpg$/)
    end

    it "should generate the medium500 url" do
      @slide.url_medium500.should match(/.jpg$/)
    end

    it "should generate the medium640 url" do
      @slide.url_medium640.should match(/_z.jpg$/)
    end

    it "should generate the large url" do
      @slide.url_large.should match(/_b.jpg$/)
    end

    it "should generate the original url" do
      @slide.url_original.should match(/_o.jpg$/)
    end
  end

  describe "finding" do
    it "should find the correct last photo" do
      # ???
    end

    it "should find the correct first photo" do
      # ???
    end
  end

  describe "context" do
    it "should return the correct previous photo" do
      # ???
    end

    it "should return the correct next photo" do
      # ???
    end
  end
end

1 个答案:

答案 0 :(得分:0)

据我所知,你应该可以做slide.stub!(:flickr).and_return来模拟不在构造函数中的任何东西。我查询了构造函数从flickr api加载的事实。

你可以改变幻灯片的实现,这样你就可以从flickr api中获取实际的方法,而不是加载attr_accessors吗?您应该能够在不更改类的外部API的情况下执行此操作,并且可以通过在实例变量中缓存api调用的结果来启用速度。

如果您仍希望在构造函数中完成所有工作,我建议使用表示flickr服务的默认参数。然后,您的构造函数将变为以下内容:

def initialize(id, flickr=flickr)
  … complicated setup code here…
end

这样,当你进行测试时,只需传入一个模拟的flickr对象:

 flickr = mock(:flickr)
 @slide = Slide.new(image_id, flickr)

然后,您可以针对新的flickr对象编写通常的rspec断言(同样,不更改外部api)。