Skip to content

Instantly share code, notes, and snippets.

@s6577t
Created January 31, 2012 23:34

Revisions

  1. s6577t renamed this gist Jan 31, 2012. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gistfile1.txt → gistfile1.rb
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    # Here is a normal set of specs...

    describe 'some normal rspec' do
  2. s6577t created this gist Jan 31, 2012.
    130 changes: 130 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,130 @@

    # 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
    #