Testing Feedzirra
For one of my side-projects I’m using Feedzirra, a robust feed parsing library. Since we all TATFT I wanted to test parts of my code that depend on feed parsing.
The glitch is that Feedzirra doesn’t work with FakeWeb, since it’s using cURL for remote connections. However cURL supports file:// protocol, so you can fake external requests with local files. I’m using Shoulda in the following examples.
app/models/feed_storage.rb# Excerpts extracted from model
class FeedStorage < ActiveRecord::Base
def parse
if self.marshaled.nil?
parser = Feedzirra::Feed.fetch_and_parse self.feed.url
entries = parser.entries
else
parser = Marshal.load self.marshaled
parser = Feedzirra::Feed.update parser
entries = parser.new_entries
end
self.update_attribute :marshaled, (Marshal.dump parser)
entries
end
end
test/unit/feed_storage_test.rb# Excerpts extracted from model's tests
class FeedStorageTest < ActiveSupport::TestCase
context "a new feed" do
setup do
@feed = Factory :feed
@feed.update_attribute :url, "file://#{URI.escape(File.join(File.dirname(File.expand_path(__FILE__, Dir.getwd)), "..", "fixtures", "full_feed.rss"))}"
end
should "setup a new parser and parse all entries" do
assert_equal 50, @feed.parser.parse.length
end
end
context "a parsed feed" do
setup do
@feed_path = "#{URI.escape(File.join(File.dirname(File.expand_path(__FILE__, Dir.getwd)), "..", "fixtures"))}"
`cp #{File.join @feed_path, "full_feed.rss"} #{File.join @feed_path, "feed.rss"}`
@feed = Factory :feed
@feed.update_attribute :url, "file://#{File.join @feed_path, "feed.rss"}"
@feed.parser.parse
`cp #{File.join @feed_path, "updated_feed.rss"} #{File.join @feed_path, "feed.rss"}`
end
should "parse all new entries" do
assert_equal 1, @feed.parser.parse.length
end
teardown do
`rm -f #{File.join @feed_path, "feed.rss"}`
end
end
end
The logic behing FeedStorage is quite simple - for every feed in the database I store its feed parser (a marshaled Ruby object, might switch to something else if I run into performance issues). Feed class requires valid urls for url field, hence the update_attribute call.
Feel free to drop me a line in the comments - I’m sure there’s some room for improvements!