Saturday, June 28, 2008

Hide external access behind a small facade for easy mocking

Imagine you have validation like this, where you call the youtube website to make sure the provided video id is valid:


1 class Video < ActiveRecord::Base
2 def validate
3 response = Net::HTTP.start('youtube.com') { |http| http.head("/v/#{self.youtube_video_id}") }
4 unless response.is_a?(Net::HTTPOK)
5 errors.add(:youtube_video_id, "no valid Youtube Video ID")
6 end
7 end
8 end
9
Actually, this code fragment is a pain in the neck to test. If you hide the external access behind a small facade (or wrapper if you like) like this:

    1 class YouTube
2 def self.video_id_valid?(video_id)
3 response = Net::HTTP.start('youtube.com') do |http|
4 http.head("/v/#{self.youtube_video_id}")
5 end
6 response.is_a?(:Net::HTTPOK)
7 end
8 end
9
10 class Video < ActiveRecord::Base
11 def validate
12 unless Youtube.video_id_valid?(self.youtube_video_id)
13 errors.add(:youtube_video_id, "no valid Youtube Video ID")
14 end
15 end
16 end
17
it's much easier to test:

    1 # video_spec.rb
2 describe Video, "validations" do
3 before(:each) do
4 @video = Video.new(:youtube_video_id => 'iY6VroKoB8E')
5 end
6 it "should succeed with correct youtube video id" do
7 Youtube.stub!(:video_id_valid?).and_return(true)
8 @video.should be_valid
9 end
10 it "should fail with incorrect youtube video id" do
11 Youtube.stub!(:video_id_valid?).and_return(false)
12 @video.should_not be_valid
13 end
14 end
15

No comments: