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