Skip to content

Instantly share code, notes, and snippets.

@sjltaylor
Created January 31, 2012 23:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sjltaylor/1713820 to your computer and use it in GitHub Desktop.
Save sjltaylor/1713820 to your computer and use it in GitHub Desktop.
My rspec fantasy
# Here is a normal set of specs...
describe 'some normal rspec' do
describe 'doing something with a Product and Users' do
before :each do
# setup etc
# preconditions could go here
User.count.should be > 5
Product.all.any?{|p| p.discontinued?}.should be true
end
def dispatch
@result = do_something with: [Product, User]
end
it 'should have called something' do
# assertions before the fact without spies :(
Api.should_receive(:some_message)
dispatch
end
it 'uses an implicit return value when calling should' do
dispatch.should == :returned_result_from_act
end
context 'doing that something with special options' do
# runs the preconditions fom the outer describe and the following
before :each do
# more preconditions
end
def dispatch
do_something with: [Product, User], some_special_option: true
end
it 'behaves differently somehow' do
dispatch.should == :something_else
end
end
end
end
# Here is how I would LIKE to write them ...
describe 'my rspec fantasy feature spies and some new api' do
describe 'doing something with a Product and Users' do
before :each do
# setup etc
end
# these would run before all specs
preconditions do
precondition 'five users' { User.count.should be > 5 }
precondition 'a discontinued product' { Product.all.any?{|p| p.discontinued?}.should be true }
end
act { do_something with: [Product, User] }
it 'should have called something' do
# assertions AFTER the fact
Api.should have_received(:some_message)
end
it 'uses an implicit return value when calling should' do
should == :returned_result_from_act
end
context 'doing that something with special options' do
# runs the preconditions fom the outer describe and the following
preconditions do
preconditions 'etc' { }
end
# this act overrides the act in the outer describe block
act { do_something with: [Product, User], some_special_option: true }
it 'behaves differently somehow' do
should == :something_else
end
end
end
end
# Here's why:
#
# I like to use test spies rather than mock-expectations because then I can stay consistent with the xunit pattern
#
# * Arrange
# * Act
# * Assert
#
# This means that I can separate the different concerns in writing my specs and introduce preconditions:
#
# * Arrange the environment
# * Assert preconditions
# * Act
# * Assert postconditions
#
# Preconditions mean that the test runner can avoid unnecessarily running specs with failing preconditions and best of all, it means I can get rspec --doc output like this:
#
# my rspec fantasy
# doing something with a Product and Users
# precondition failed: 'five users'
#
# When this failure occurs I know exactly why my specs have not been run and what to do next to fix the suite. with
#
# it also provides a way to separate and DRY the ACT
# * it calls can be simple one-liners and only have one concern: assertion
# * the act can be defined ONCE and run implicitly
#
# this also means that I can start sketching out my specs by just writing the assertions and preconditions and worry about the arrange and act details later in the BDD process.
#
#
# Each syntax yields roughly the same number of lines in this small example. Larger examples may lead to fewer lines of code as a result of being DRYed up.
#
# Overall the benefits would be
# * clearer more consistently structured specs and...
# * better spec output leading to...
# * more maintainable spec suites
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment