如何在应用程序的单元测试中删除 flickraw 库?

发布于 2024-09-15 14:33:47 字数 3361 浏览 7 评论 0原文

我的 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

My Rails 2 app displays a slideshow of photos from Flickr via the flickraw library. My code works, but I'm stuck on how to properly write RSpec unit tests.

I have a Slide class that encapsulates everything that my app needs from flickraw. It acts somewhat like a model object but doesn't use ActiveRecord. It doesn't do much work; it delegates most of the heavy lifting to flickraw.

I haven't completed the tests because, as it is now, they require me to hard-code in some photo IDs from Flickr, and the tests would break if I rearranged my photoset or added new photos.

So my so-called unit tests are more like integration tests. I understand how to write a mock or stub using RSpec, but not sure how to do it to the flickraw library. How do I stub out flickraw and turn this into a unit test?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

〃安静 2024-09-22 14:33:47

据我了解,您应该能够执行 slip.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)。

As I understand it, you should be able to do slide.stub!(:flickr).and_return to mock out anything that isn't inside the constructor. I query the fact that the constructor is loading so much from the flickr api though.

Can you change the implementation of slide so that instead of a load of attr_accessors, you have actual methods that get stuff from the flickr api? You should be able to do this without changing the external api of the class, and you can enable speed via caching the results of api calls in instance variables.

If you still want to have all that work done in the constructor, I'd recommend having a default argument that represents the flickr service. Your constructor then becomes the following:

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

This way, when you're testing, just pass in a mock flickr object like so:

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

You can then write the usual rspec assertions against the new flickr object (again, without changing the external api).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文