On 7/26/07, Jacob A. [email protected] wrote:
This sounds very interesting. I would love to see a concrete example
detailing your approach.
Okay, here we go 
describe VideoService, " when creating a video" do
fixtures :companies, :sites, :video_formats, :publish_settings
before(:each) do
@video = Video.new
@video.company = companies(:test)
@video.site = sites(:test)
sites(:test).stub!(:formats).and_return [ video_formats(:flash) ]
@origin = mock_model(Origin, :process_source => true,
:transcode_asset => true, :storage => “file”)
Origin.stub!(:find_transcoder).and_return @origin
@service = VideoService.new
end
def create_video
@service.create_video :video => @video, :signature => “abc123”,
:frame => 1, :storage => “file”
end
it “should add a new video record” do
lambda { create_video }.should change(Video, :count).by(1)
end
it “should create two assets - one source and one transcoded” do
lambda { create_video }.should change(Asset, :count).by(2)
@video.source_asset.should be_source
@video.should have(2).assets
end
it “should create the main asset with the appropriate video format” do
create_video
@video.assets.find_by_video_format_id(video_formats(:flash).id).should_not
be_blank
end
end
describe VideoService, " when creating a video" do
fixtures :companies, :sites, :video_formats
before(:each) do
@video = mock_model(Video, :save => true, :company_id =>
companies(:test).id, :site => sites(:test), :hook => nil)
sites(:test).stub!(:formats).and_return [ video_formats(:flash) ]
@source_asset = mock_model(Asset, :video_id= => @video.id, :save =>
true)
@transcode_asset = mock_model(Asset, :video_id= => @video.id, :save
=> true)
Asset.stub!(:new).and_return @source_asset, @transcode_asset
@video.stub!(:source_asset).and_return @source_asset
@source_origin = mock_model(Origin, :process_source => true,
:transcode_asset => true, :storage => “file”)
@transcode_origin = mock_model(Origin, :transcode_asset => true,
:storage => “file”)
Origin.stub!(:find_transcoder).and_return @source_origin,
@transcode_origin
@service = VideoService.new
end
def create_video
@service.create_video :video => @video, :signature => “abc123”,
:frame => 1, :storage => “file”
end
it “should find a transcoder” do
Origin.should_receive(:find_transcoder).with(companies(:test).id,
false, “file”).and_return @source_origin
create_video
end
it “should process the source asset” do
@source_origin.should_receive(:process_source).with(“abc123”,
@source_asset, 1, “http://test.host:80/”)
create_video
end
it “should find an origin for the transcode format” do
Origin.should_receive(:find_transcoder).with(companies(:test).id,
false, nil).and_return @transcode_origin
create_video
end
it “should transcode the new asset” do
@transcode_origin.should_receive(:transcode_asset).with(“abc123”,
@transcode_asset, “http://test.host:80/”,
“http://test.host:80/video_formats/#{video_formats(:flash).id}.xml”)
create_video
end
end
I created the VideoService to wrap the creation of a video in our
system. At that stage in the code, there were a couple main parts -
creating a new video record, creating a couple asset records, and
notifying our transcode machines about the new assets.
The first example specifies the db behavior I want. That was my
black-box test (you might say it’s grey-box because I’m stubbing some
stuff out, but that wasn’t part of the original spec. It’s just there
so the spec can run - Origin makes a network call and it’s easier to
stub the whole thing out).
The second example is the white-box test, which verifies that the
internals work. Certain origins should be found, they need to receive
certain calls with a particular video, etc.
Now I’m not sure if people will like those specs
but hopefully it
gives you an idea of how you can approach specifications from both
angles.
Pat