如何在应用程序的单元测试中删除 flickraw 库?
我的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
据我了解,您应该能够执行 slip.stub!(:flickr).and_return 来模拟不在构造函数内的任何内容。我质疑构造函数从 flickr api 加载了如此之多的事实。
您能否更改幻灯片的实现,以便您拥有从 flickr api 获取内容的实际方法,而不是大量的 attr_accessors?您应该能够在不更改类的外部 api 的情况下执行此操作,并且可以通过在实例变量中缓存 api 调用的结果来提高速度。
如果您仍然希望在构造函数中完成所有工作,我建议使用一个代表 flickr 服务的默认参数。然后,您的构造函数将变为以下内容:
这样,当您进行测试时,只需传入一个模拟 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:
This way, when you're testing, just pass in a mock flickr object like so:
You can then write the usual rspec assertions against the new flickr object (again, without changing the external api).