Hello,
I’ve been thinking of how to express my idea in code, but since I’ve
never
been involved in RSpec development, I’d better have some feedback here
first.
The feature suggestion below applies to any controller-like code under
spec,
i.e. a stateless module producing output or just altering its data store
(it
doesn’t necessarily have to be a C of the MVC, but I suppose merb/rails
developers will particularly appreciate it).
Here is a skimmed sample to illustrate the pain:
describe BookController do
context "registering a book" do
specify "from a new author on a new subject" do
auth = mock(:name => 'John D.')
Author.should_receive(:find_
by_name).and_return(nil)
Author.should_receive(:new).and_return(auth)
auth.should_receive(:save).and_return(true)
subj = mock(:short => 'Mockery')
Subject.should_receive(:find_by_short).and_return(nil)
Subject.should_receive(:new).and_return(subj)
subj.should_receive(:save).and_return(true)
title = 'Specs on Steroids'
book = mock
Book.should_receive(:new).and_return(book)
book.should_receive(:save).and_return(true)
post :register :author => auth.name, :title => title, :subject
=>
subj.short
response.should be_success
end
specify "from a known author on a new subject" do
auth = mock(:name => 'Joe Dohn')
Author.should_receive(:find_by_name).and_return(auth)
subj = mock(:short => 'Mockery')
Subject.should_receive(:find_by_short).and_return(nil)
Subject.should_receive(:new).and_return(subj)
subj.should_receive(:save).and_return(true)
title = 'Specs on Steroids II'
book = mock
Book.should_receive(:new).and_return(book)
book.should_receive(:save).and_return(true)
post :register :author => auth.name, :title => title, :subject
=>
subj.short
response.should be_success
end
specify "from a known author on a known subject" do
auth = mock(:name => 'Joe Dohn')
Author.should_receive(:find_by_name).and_return(auth)
subj = mock(:short => 'Forgery')
Subject.should_receive(:find_by_short).and_return(subj)
#...
end
specify "from a new author on a known subject" do
#...
end
end
end
And this is what I have in mind for doing exactly the same job:
describe BookController do
context "registering a book" do
before :any, "from a new author", :author do
@auth = mock(:name => 'John D.')
Author.should_receive(:find_by_name).and_return(nil)
Author.should_receive(:new).and_return(@auth)
@auth.should_receive(:save).and_return(true)
end
before :any, "from a known author", :author do
@auth = mock(:name => 'Joe Dohn')
Author.should_receive(:find_by_name).and_return(@auth)
end
before :any, "on a new subject", :subject do
@subj = mock(:short => 'Mockery')
Subject.should_receive(:find_by_short).and_return(nil)
Subject.should_receive(:new).and_return(@subj)
@subj.should_receive(:save).and_return(true)
end
before :any, "on a known subject", :subject do
@subj = mock(:name => 'Joe Dohn')
Subject.should_receive(:find_by_name).and_return(@subj)
end
it "should succeed", :with => [:author, :subject] do
title = 'Specs on Steroids X'
post :register :author => @auth.name, :title => title,
:subject =>
@subj.short
response.should be_success
end
end
end
A run of such specs will effectively multiply the tests — automatically
—
choosing before and after blocks as specified.
I’m sorry, I haven’t thought the DSL through, but I hope the main idea
can
be seen: contexts do not have to be hierarchical.
In my opinion, adding some sort of context selection+combination
capabilities (AOP-style) will contribute greatly to the expressiveness
of
the spec language.
Thank you for your attention,
Costa.