Skip to content

Instantly share code, notes, and snippets.

@levity
Forked from dnagir/rspec-syntax-cheat-sheet.rb
Created November 28, 2011 20:10

Revisions

  1. Lawrence Wang revised this gist Nov 28, 2011. 1 changed file with 86 additions and 86 deletions.
    172 changes: 86 additions & 86 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -3,53 +3,53 @@
    # defining spec within a module will automatically pick Player::MovieList as a 'subject' (see below)
    module Player
    describe MovieList, "with optional description" do

    it "is pending example, so that you can write ones quickly"

    it "is already working example that we want to suspend from failing temporarily" do
    pending("working on another feature that temporarily breaks this one")
    # actual test code is here, will never be reached
    pending("working on another feature that temporarily breaks this one")
    # actual test code is here, will never be reached
    end

    it "is pending when failing" do
    pending "This will be marked as pending when the block will fail, otherwise (on success) will fail telling 'Why am I pending if I pass?'" do
    1.should == 2 # will mark example as pending
    2.should == 2 # will fail asking to remove pending status of example
    end
    end

    # this will automatically generate name of the example based on the expectations inside it ~ 'it' with no description
    specify { [1,2,3].should have(3).items }

    #any helper methods, before/after, modules etc declared in the outer group are available in the inner group.
    describe "outer" do
    before(:each) { puts "first" }
    describe "inner" do
    before(:each) { puts "second" }
    it { puts "third"}
    after(:each) { puts "fourth" }
    before(:each) { puts "second" }
    it { puts "third"}
    after(:each) { puts "fourth" }
    end
    after(:each) { puts "fifth" }
    end

    # 'describe' and 'context' are equivalent
    # I prefer to use 'context' for defining an 'environment'
    context "when first created" do
    it "is empty" do
    movie_list = MovieList.new
    movie_list.should be_empty
    end
    it "is empty" do
    movie_list = MovieList.new
    movie_list.should be_empty
    end
    end

    # I prefer to use 'describe' for nouns, verbs; defining a nested set of specifications
    describe "forward" do
    it "should jump to a next movie" do
    next_movie = MovieList.new(2).forward
    next_movie.track_number.should == 2
    end
    it "should jump to a next movie" do
    next_movie = MovieList.new(2).forward
    next_movie.track_number.should == 2
    end
    end
    end

    it "will have default subject that corresponds to the instance of first parameter in 'describe'" do
    subject.class.should be == MovieList
    end
    @@ -58,7 +58,7 @@ module Player
    # no need to use 'subject.should', use 'should'
    specify { should have(10).items } # same as below
    specify { subject.should have(10).items }


    # similar to specify { subject.track_number.should == 1}
    its(:track_number) { should == 1 }
    @@ -79,7 +79,7 @@ module Player
    @new_on_each_example.should_not be_nil
    @same_instance_for_all_examples_within_the_context.should_not be_nil
    end

    # cleanup code can be run the same way using 'after' instead of 'before'
    # Avoid using 'after'
    # we can wrap examples: before + after + manual handling
    @@ -94,14 +94,14 @@ module Player
    it "should run within a transaction" do
    MovieList.new.save!
    end

    let(:new_on_each_example) { ObjectPerExample.new }
    it "can use method defined by 'let'" do
    new_on_each_example.should_not be_nil
    # the object is memoized, so
    new_on_each_example.should == new_on_each_example
    end

    # defining helper methods within context may be more useful than setup
    def forward(times) do
    list = MoviewList.new(10)
    @@ -112,7 +112,7 @@ def forward(times) do
    forward(2).should == 2
    forward(10).should == 1
    end

    # using 'yield' with helper methods
    def given_thing_with(options)
    yield Thing.new do |thing|
    @@ -124,8 +124,8 @@ def given_thing_with(options)
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    end
    end


    # helpers can come from modules
    module Helpers
    def shared_help
    @@ -141,15 +141,15 @@ def shared_help
    # config.include Helpers
    # end
    end


    context "built-it stubbing, faking, mocking" do
    it "can stub" do
    source = double('source')
    source.stub(:fetch) { [1,2,3,4,5] }
    source.stub(:fetch_from).and_return([1,2]) # other way
    MovieList.stub(:find).and_return(MovieList.new) # stub class method

    implementing = double('source')
    implementing.stub(:fetch) do |count|
    count == 5 ? [1,2,3] : [4,5,6,7] # provide stub logic here, easy to use for Fakes
    @@ -200,12 +200,12 @@ def shared_help
    source.should_recieve(:fetch).never
    source.should_recieve(:fetch).exactly(0)times
    source.should_not_recieve(:fetch)


    list = MovieList.new(source)
    # if source.fetch has not been called, then example will fail
    end

    context "custom expectations" do
    # define custom expection class somewhere
    class GreaterThanMatcher
    @@ -221,35 +221,35 @@ def ==(actual)
    actual > @expected
    end
    end

    # add this method to the RSpec (see set-up for global configuration)
    def greater_than(floor)
    GreaterThanMatcher.new(floor)
    end

    it "can be used in expectations" do
    subject.should_recieve(:forward).with(greater_than 3)
    subject.forward(5)
    end
    end # custom matchers
    end # mocking









    # set of same examples shared accross multiple specs
    # shared_examples_for should be in a separate file and defined outside of 'describe'/'context'
    shared_examples_for "any pizza" do
    it "tastes really good" do
    @pizza.should taste_really_good
    end
    end

    # to include the shared examples, into example groups:
    # it will assume @pizza instance variable is available here
    it_behaves_like "any pizza"

    context 'defining examples dynamically - everybody knows that :)' do
    {2 => 4, 3 => 6, 10 => 20}.each do |input, output|
    it "#{input} * 2 should be equal to #{output}" do
    @@ -261,8 +261,8 @@ def greater_than(floor)
    end
    end
    end


    context "matchers" do
    it "shows built-in matchers" do
    # TODO: describe ===, eql, equal
    @@ -277,17 +277,17 @@ def greater_than(floor)
    "reg exp".should =~ /exp/
    [1,2].should include(1)
    1.should respond_to(:to_s)

    true.should be_true
    0.should be_true
    "this".should be_true

    lambda { Object.new.explodde! }.should raise_error(NameError)

    # nothing fits
    5.should satisfy { |it| it == 5 }
    end

    it "shows cool things" do
    count = 1
    expect {
    @@ -297,59 +297,59 @@ def greater_than(floor)
    expect {
    # not changing
    }.to_not change { count }

    count = 1
    expect {
    count = 3
    }.to change { count }.to(3)

    count = 1
    expect {
    count = 3
    }.to change { count }from(1).to(3)

    # raise-rescue - exception handling
    expect {2 / 0}.to raise_error("divided by 0")
    expect {2 / 0}.to raise_error(/by 0/)
    expect {2 / 0}.to raise_error(ZeroDivisionError)

    # try-catch - expected circumstance handling
    lambda { throw :room_is_full }.should throw_symbol(:room_is_full)

    # predicates
    nil.should be_nil #call nil.nil?
    [].should be_empty # calls [].empty?
    [1,2,3].should_not be_empty # calls [1,2,3].empty

    # convert anything that begins with have_ to a predicate on the target object beginning with has_
    {:id => 1}.has_key?(:id).should == true
    # can be written as
    {:id => 1}.should have_key(:id) # calls {:id => 1}.has_key?(:id)

    # collections
    obj = {}
    def obj.numbers
    [1,2,3,4]
    [1,2,3,4]
    end

    obj.should have(4).numbers # calls obj.numbers.length
    [1,2,3,4].should have(4).items # 'items' is 'reserved' to say "ensure number of items on the collection"
    [1,2,3,4].should be_any {|n| n % 2 == 0} # [1,2,3,4].any? {|n| n %% 2 == 0}.should be_true
    "stringy".should have(7).charaters # same as items, just syntactic sugar
    [1,2,3,4].should have_exactly(24).items # same as 'have'
    obj.should have_at_least(3).numbers


    end
    end # built-in matchers





    context "custom matchers" do
    # TODO: describe multiple ways

    #define class
    class SimilarTo
    # mandatory - link to the object under test
    @@ -381,42 +381,42 @@ def description
    "#{@it} should be similar to #{@that}"
    end
    end

    #define method on example (see set-up to incude in all examples)
    def similar_to(that)
    SimilarTo.new(that)
    end
    end # custom matchers




    context "macros" do
    module ControllerMacros
    def should_render(template)
    it "should render the #{template} template" do
    do_request
    response.should render_template(template)
    end
    it "should render the #{template} template" do
    do_request
    response.should render_template(template)
    end
    end

    def should_assign(hash)
    variable_name = hash.keys.first
    model, method = hash[variable_name]
    model_access_method = [model, method].join('.')
    it "should assign @#{variable_name} => #{model_access_method}" do
    expected = "the value returned by #{model_access_method}"
    model.should_receive(method).and_return(expected)
    do_request
    assigns[variable_name].should == expected
    end
    variable_name = hash.keys.first
    model, method = hash[variable_name]
    model_access_method = [model, method].join('.')
    it "should assign @#{variable_name} => #{model_access_method}" do
    expected = "the value returned by #{model_access_method}"
    model.should_receive(method).and_return(expected)
    do_request
    assigns[variable_name].should == expected
    end
    end

    def get(action)
    define_method :do_request do
    get action
    end
    yield
    define_method :do_request do
    get action
    end
    yield
    end
    end

    @@ -427,5 +427,5 @@ def get(action)
    config.extend(ControllerMacros, :type => :controller)
    end
    end # macros

    end # module
  2. Lawrence Wang revised this gist Nov 28, 2011. 1 changed file with 417 additions and 417 deletions.
    834 changes: 417 additions & 417 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -2,430 +2,430 @@

    # defining spec within a module will automatically pick Player::MovieList as a 'subject' (see below)
    module Player
    describe MovieList, "with optional description" do
    it "is pending example, so that you can write ones quickly"
    it "is already working example that we want to suspend from failing temporarily" do
    pending("working on another feature that temporarily breaks this one")
    # actual test code is here, will never be reached
    end
    it "is pending when failing" do
    pending "This will be marked as pending when the block will fail, otherwise (on success) will fail telling 'Why am I pending if I pass?'" do
    1.should == 2 # will mark example as pending
    2.should == 2 # will fail asking to remove pending status of example
    end
    end
    # this will automatically generate name of the example based on the expectations inside it ~ 'it' with no description
    specify { [1,2,3].should have(3).items }
    #any helper methods, before/after, modules etc declared in the outer group are available in the inner group.
    describe "outer" do
    before(:each) { puts "first" }
    describe "inner" do
    before(:each) { puts "second" }
    it { puts "third"}
    after(:each) { puts "fourth" }
    end
    after(:each) { puts "fifth" }
    end
    describe MovieList, "with optional description" do
    it "is pending example, so that you can write ones quickly"
    it "is already working example that we want to suspend from failing temporarily" do
    pending("working on another feature that temporarily breaks this one")
    # actual test code is here, will never be reached
    end
    it "is pending when failing" do
    pending "This will be marked as pending when the block will fail, otherwise (on success) will fail telling 'Why am I pending if I pass?'" do
    1.should == 2 # will mark example as pending
    2.should == 2 # will fail asking to remove pending status of example
    end
    end
    # this will automatically generate name of the example based on the expectations inside it ~ 'it' with no description
    specify { [1,2,3].should have(3).items }
    #any helper methods, before/after, modules etc declared in the outer group are available in the inner group.
    describe "outer" do
    before(:each) { puts "first" }
    describe "inner" do
    before(:each) { puts "second" }
    it { puts "third"}
    after(:each) { puts "fourth" }
    end
    after(:each) { puts "fifth" }
    end

    # 'describe' and 'context' are equivalent
    # I prefer to use 'context' for defining an 'environment'
    context "when first created" do
    it "is empty" do
    movie_list = MovieList.new
    movie_list.should be_empty
    end
    end
    # 'describe' and 'context' are equivalent
    # I prefer to use 'context' for defining an 'environment'
    context "when first created" do
    it "is empty" do
    movie_list = MovieList.new
    movie_list.should be_empty
    end
    end

    # I prefer to use 'describe' for nouns, verbs; defining a nested set of specifications
    describe "forward" do
    it "should jump to a next movie" do
    next_movie = MovieList.new(2).forward
    next_movie.track_number.should == 2
    end
    end
    end
    it "will have default subject that corresponds to the instance of first parameter in 'describe'" do
    subject.class.should be == MovieList
    end
    # unless subject is set explicitly
    subject { MovieList.new(10) } # approximately similar to 'before(:each)'
    # no need to use 'subject.should', use 'should'
    specify { should have(10).items } # same as below
    specify { subject.should have(10).items }
    # I prefer to use 'describe' for nouns, verbs; defining a nested set of specifications
    describe "forward" do
    it "should jump to a next movie" do
    next_movie = MovieList.new(2).forward
    next_movie.track_number.should == 2
    end
    end
    end
    it "will have default subject that corresponds to the instance of first parameter in 'describe'" do
    subject.class.should be == MovieList
    end
    # unless subject is set explicitly
    subject { MovieList.new(10) } # approximately similar to 'before(:each)'
    # no need to use 'subject.should', use 'should'
    specify { should have(10).items } # same as below
    specify { subject.should have(10).items }

    # similar to specify { subject.track_number.should == 1}
    its(:track_number) { should == 1 }
    # similar to specify { subject.track_number.should == 1}
    its(:track_number) { should == 1 }

    context "specs set-up" do
    # we can run setup before each examle, or all of them
    before(:each) do
    @new_on_each_example = YourObject.new
    end
    before do
    @new_on_each_spec_less_verbose = YourObject.new
    end
    before(:all) do
    # Avoid using it as it will bring the 'shared state' into unit tests
    @same_instance_for_all_examples_within_the_context = YourObject.new
    end
    it "can access attributes defined in 'before'" do
    @new_on_each_example.should_not be_nil
    @same_instance_for_all_examples_within_the_context.should_not be_nil
    end
    # cleanup code can be run the same way using 'after' instead of 'before'
    # Avoid using 'after'
    # we can wrap examples: before + after + manual handling
    # In most cases 'before' + 'after' will work better.
    around do |example|
    DB.transaction { example.run }
    # should handle errors manually, so do not do something like:
    # DB.start_transaction
    # example.run
    # DB.rollback_transaction
    end
    it "should run within a transaction" do
    MovieList.new.save!
    end
    let(:new_on_each_example) { ObjectPerExample.new }
    it "can use method defined by 'let'" do
    new_on_each_example.should_not be_nil
    # the object is memoized, so
    new_on_each_example.should == new_on_each_example
    end
    # defining helper methods within context may be more useful than setup
    def forward(times) do
    list = MoviewList.new(10)
    list.forward(times).track_number
    end
    it "can use it multiple times" do
    forward(1).should == 1
    forward(2).should == 2
    forward(10).should == 1
    end
    # using 'yield' with helper methods
    def given_thing_with(options)
    yield Thing.new do |thing|
    thing.set_status(options[:status])
    end
    end
    it "should do something when ok" do
    given_thing_with(:status => 'ok') do |thing|
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    end
    end
    # helpers can come from modules
    module Helpers
    def shared_help
    [1,2,3]
    end
    end
    include Helpers
    it "can use helpers from Module" do
    shared_help.should == [1,2,3]
    end
    # or this module can be included for ALL example groups automatically during configuration:
    # RSpec.configure do |config|
    # config.include Helpers
    # end
    end
    context "built-it stubbing, faking, mocking" do
    it "can stub" do
    source = double('source')
    source.stub(:fetch) { [1,2,3,4,5] }
    source.stub(:fetch_from).and_return([1,2]) # other way
    MovieList.stub(:find).and_return(MovieList.new) # stub class method
    implementing = double('source')
    implementing.stub(:fetch) do |count|
    count == 5 ? [1,2,3] : [4,5,6,7] # provide stub logic here, easy to use for Fakes
    end
    # easily stub chains of calls
    Blog.stub_chain(:posts, :published, :recent).and_return([1,2,3])
    Blog.posts.published.recent.should == [1,2,3]
    end
    it "can ignore non-expected method calls (NullObject pattern)" do
    source = double('source', :url => 'http://example.com').as_null_object
    source.any_method_call_onwill_return_nil.should be_nil
    # the source mock object will record the 'any_method_call_onwill_return_nil' message internally though
    end
    it "can set expectations" do
    source = double('source')
    # arguments
    source.should_receive(:fetch).with(10, "abc").and_return([1,2]) # expecting arguments (10, "abc") otherwise failing
    source.should_receive(:fetch).with(instance_of(Integer), "abc").and_return([1,2]) # don't care about 1st argument as long as it is Integer
    source.should_receive(:fetch).with(10, anything).and_return([1,2]) # don't care about 2nd argument at all
    source.should_receive(:fetch).with(any_args) # same as not using 'with' - don't care about arguments
    source.should_receive(:fetch).with(no_args) # 0 arguments, otherwise fail
    source.should_receive(:fetch).with(hash_including(:count => 10, :url => 'abc')) # arg should be Hash with all the values mentioned
    source.should_receive(:fetch).with(hash_not_including(:timeout => 5)) # arg should be Hash that contains no ':timout=>5'
    source.should_receive(:fetch).with(anything, /example/) # 2nd arg shuold match RegEx
    source.should_receive(:fetch).and_return([1], [1,2], [1,2,3]) # 1st call - [1], 2nd - [1,2], 3rd - [1,2,3], 4th - [1] and so on ...
    # expectation overrides stub
    source.stub(:fetch).and_return([1,2]) # will return [1,2] when called
    source.should_recieve(:fetch).and_return([3,4]) # prev been overriden and will return [3,4]
    # raising/throwing
    source.should_receive(:fetch).and_raise # raise Exception
    source.should_receive(:fetch).and_raise(ZeroDivisionError) # raise ZeroDivisionError
    source.should_receive(:fetch).and_raise(Exception.new('instance of aexception')) # raise given exception
    source.should_receive(:fetch).and_throw(:zero) # thro :zero
    # order
    source.should_receive(:first).ordered # order matters in relation to others marked as ordered
    source.should_receive(:dosnt_matter) # don't care about order as long as it is called
    source.should_receive(:second).ordered # must be called after 'first'
    # order is not enforced across different objects:
    double('a').should_receive(:a).ordered # not related to the next one
    double('b').should_receive(:b).ordered # not related to the prev one
    # how many times?
    source.should_recieve(:fetch).exactly(1)times
    source.should_recieve(:fetch).at_most(5)times
    source.should_recieve(:fetch).at_least(2)times
    source.should_recieve(:fetch).twice
    source.should_recieve(:fetch).once
    # negative expectations
    source.should_recieve(:fetch).never
    source.should_recieve(:fetch).exactly(0)times
    source.should_not_recieve(:fetch)
    list = MovieList.new(source)
    # if source.fetch has not been called, then example will fail
    end
    context "custom expectations" do
    # define custom expection class somewhere
    class GreaterThanMatcher
    def initialize(expected)
    @expected = expected
    end
    def description
    # will generate proper failure message and name of the example
    "a number greater than #{@expected}"
    end
    def ==(actual)
    # this will be called from
    actual > @expected
    end
    end
    # add this method to the RSpec (see set-up for global configuration)
    def greater_than(floor)
    GreaterThanMatcher.new(floor)
    end
    it "can be used in expectations" do
    subject.should_recieve(:forward).with(greater_than 3)
    subject.forward(5)
    end
    end # custom matchers
    end # mocking
    context "specs set-up" do
    # we can run setup before each examle, or all of them
    before(:each) do
    @new_on_each_example = YourObject.new
    end
    before do
    @new_on_each_spec_less_verbose = YourObject.new
    end
    before(:all) do
    # Avoid using it as it will bring the 'shared state' into unit tests
    @same_instance_for_all_examples_within_the_context = YourObject.new
    end
    it "can access attributes defined in 'before'" do
    @new_on_each_example.should_not be_nil
    @same_instance_for_all_examples_within_the_context.should_not be_nil
    end
    # cleanup code can be run the same way using 'after' instead of 'before'
    # Avoid using 'after'
    # we can wrap examples: before + after + manual handling
    # In most cases 'before' + 'after' will work better.
    around do |example|
    DB.transaction { example.run }
    # should handle errors manually, so do not do something like:
    # DB.start_transaction
    # example.run
    # DB.rollback_transaction
    end
    it "should run within a transaction" do
    MovieList.new.save!
    end
    let(:new_on_each_example) { ObjectPerExample.new }
    it "can use method defined by 'let'" do
    new_on_each_example.should_not be_nil
    # the object is memoized, so
    new_on_each_example.should == new_on_each_example
    end
    # defining helper methods within context may be more useful than setup
    def forward(times) do
    list = MoviewList.new(10)
    list.forward(times).track_number
    end
    it "can use it multiple times" do
    forward(1).should == 1
    forward(2).should == 2
    forward(10).should == 1
    end
    # using 'yield' with helper methods
    def given_thing_with(options)
    yield Thing.new do |thing|
    thing.set_status(options[:status])
    end
    end
    it "should do something when ok" do
    given_thing_with(:status => 'ok') do |thing|
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    end
    end
    # helpers can come from modules
    module Helpers
    def shared_help
    [1,2,3]
    end
    end
    include Helpers
    it "can use helpers from Module" do
    shared_help.should == [1,2,3]
    end
    # or this module can be included for ALL example groups automatically during configuration:
    # RSpec.configure do |config|
    # config.include Helpers
    # end
    end
    context "built-it stubbing, faking, mocking" do
    it "can stub" do
    source = double('source')
    source.stub(:fetch) { [1,2,3,4,5] }
    source.stub(:fetch_from).and_return([1,2]) # other way
    MovieList.stub(:find).and_return(MovieList.new) # stub class method
    implementing = double('source')
    implementing.stub(:fetch) do |count|
    count == 5 ? [1,2,3] : [4,5,6,7] # provide stub logic here, easy to use for Fakes
    end
    # easily stub chains of calls
    Blog.stub_chain(:posts, :published, :recent).and_return([1,2,3])
    Blog.posts.published.recent.should == [1,2,3]
    end
    it "can ignore non-expected method calls (NullObject pattern)" do
    source = double('source', :url => 'http://example.com').as_null_object
    source.any_method_call_onwill_return_nil.should be_nil
    # the source mock object will record the 'any_method_call_onwill_return_nil' message internally though
    end
    it "can set expectations" do
    source = double('source')
    # arguments
    source.should_receive(:fetch).with(10, "abc").and_return([1,2]) # expecting arguments (10, "abc") otherwise failing
    source.should_receive(:fetch).with(instance_of(Integer), "abc").and_return([1,2]) # don't care about 1st argument as long as it is Integer
    source.should_receive(:fetch).with(10, anything).and_return([1,2]) # don't care about 2nd argument at all
    source.should_receive(:fetch).with(any_args) # same as not using 'with' - don't care about arguments
    source.should_receive(:fetch).with(no_args) # 0 arguments, otherwise fail
    source.should_receive(:fetch).with(hash_including(:count => 10, :url => 'abc')) # arg should be Hash with all the values mentioned
    source.should_receive(:fetch).with(hash_not_including(:timeout => 5)) # arg should be Hash that contains no ':timout=>5'
    source.should_receive(:fetch).with(anything, /example/) # 2nd arg shuold match RegEx
    source.should_receive(:fetch).and_return([1], [1,2], [1,2,3]) # 1st call - [1], 2nd - [1,2], 3rd - [1,2,3], 4th - [1] and so on ...
    # expectation overrides stub
    source.stub(:fetch).and_return([1,2]) # will return [1,2] when called
    source.should_recieve(:fetch).and_return([3,4]) # prev been overriden and will return [3,4]
    # raising/throwing
    source.should_receive(:fetch).and_raise # raise Exception
    source.should_receive(:fetch).and_raise(ZeroDivisionError) # raise ZeroDivisionError
    source.should_receive(:fetch).and_raise(Exception.new('instance of aexception')) # raise given exception
    source.should_receive(:fetch).and_throw(:zero) # thro :zero
    # order
    source.should_receive(:first).ordered # order matters in relation to others marked as ordered
    source.should_receive(:dosnt_matter) # don't care about order as long as it is called
    source.should_receive(:second).ordered # must be called after 'first'
    # order is not enforced across different objects:
    double('a').should_receive(:a).ordered # not related to the next one
    double('b').should_receive(:b).ordered # not related to the prev one
    # how many times?
    source.should_recieve(:fetch).exactly(1)times
    source.should_recieve(:fetch).at_most(5)times
    source.should_recieve(:fetch).at_least(2)times
    source.should_recieve(:fetch).twice
    source.should_recieve(:fetch).once
    # negative expectations
    source.should_recieve(:fetch).never
    source.should_recieve(:fetch).exactly(0)times
    source.should_not_recieve(:fetch)
    list = MovieList.new(source)
    # if source.fetch has not been called, then example will fail
    end
    context "custom expectations" do
    # define custom expection class somewhere
    class GreaterThanMatcher
    def initialize(expected)
    @expected = expected
    end
    def description
    # will generate proper failure message and name of the example
    "a number greater than #{@expected}"
    end
    def ==(actual)
    # this will be called from
    actual > @expected
    end
    end
    # add this method to the RSpec (see set-up for global configuration)
    def greater_than(floor)
    GreaterThanMatcher.new(floor)
    end
    it "can be used in expectations" do
    subject.should_recieve(:forward).with(greater_than 3)
    subject.forward(5)
    end
    end # custom matchers
    end # mocking

    # set of same examples shared accross multiple specs
    # shared_examples_for should be in a separate file and defined outside of 'describe'/'context'
    shared_examples_for "any pizza" do
    it "tastes really good" do
    @pizza.should taste_really_good
    end
    end
    # to include the shared examples, into example groups:
    # it will assume @pizza instance variable is available here
    it_behaves_like "any pizza"
    context 'defining examples dynamically - everybody knows that :)' do
    {2 => 4, 3 => 6, 10 => 20}.each do |input, output|
    it "#{input} * 2 should be equal to #{output}" do
    (input * 2).should == output
    # will produce examples:
    # - 2 * 2 should be equal to 4
    # - 3 * 2 should be equal to 6
    # - 10 * 2 should be equal to 20
    end
    end
    end
    context "matchers" do
    it "shows built-in matchers" do
    # TODO: describe ===, eql, equal
    1.should == 1
    1.should_not == 2 # NOT 1.should != 2
    1.should_not equal(2) # same as above
    1.should_not == 2
    5.should be > 3
    5.should be <= 5
    (1.251).should be_close(1.25, 0.005)
    (1.251).should be_within(0.005).of 1.25 # >= RSpec 2.1
    "reg exp".should =~ /exp/
    [1,2].should include(1)
    1.should respond_to(:to_s)
    true.should be_true
    0.should be_true
    "this".should be_true
    lambda { Object.new.explodde! }.should raise_error(NameError)
    # nothing fits
    5.should satisfy { |it| it == 5 }
    end
    it "shows cool things" do
    count = 1
    expect {
    count = 3
    }.to change { count }.by(2)
    # set of same examples shared accross multiple specs
    # shared_examples_for should be in a separate file and defined outside of 'describe'/'context'
    shared_examples_for "any pizza" do
    it "tastes really good" do
    @pizza.should taste_really_good
    end
    end
    # to include the shared examples, into example groups:
    # it will assume @pizza instance variable is available here
    it_behaves_like "any pizza"
    context 'defining examples dynamically - everybody knows that :)' do
    {2 => 4, 3 => 6, 10 => 20}.each do |input, output|
    it "#{input} * 2 should be equal to #{output}" do
    (input * 2).should == output
    # will produce examples:
    # - 2 * 2 should be equal to 4
    # - 3 * 2 should be equal to 6
    # - 10 * 2 should be equal to 20
    end
    end
    end
    context "matchers" do
    it "shows built-in matchers" do
    # TODO: describe ===, eql, equal
    1.should == 1
    1.should_not == 2 # NOT 1.should != 2
    1.should_not equal(2) # same as above
    1.should_not == 2
    5.should be > 3
    5.should be <= 5
    (1.251).should be_close(1.25, 0.005)
    (1.251).should be_within(0.005).of 1.25 # >= RSpec 2.1
    "reg exp".should =~ /exp/
    [1,2].should include(1)
    1.should respond_to(:to_s)
    true.should be_true
    0.should be_true
    "this".should be_true
    lambda { Object.new.explodde! }.should raise_error(NameError)
    # nothing fits
    5.should satisfy { |it| it == 5 }
    end
    it "shows cool things" do
    count = 1
    expect {
    count = 3
    }.to change { count }.by(2)

    expect {
    # not changing
    }.to_not change { count }
    count = 1
    expect {
    count = 3
    }.to change { count }.to(3)
    count = 1
    expect {
    count = 3
    }.to change { count }from(1).to(3)
    # raise-rescue - exception handling
    expect {2 / 0}.to raise_error("divided by 0")
    expect {2 / 0}.to raise_error(/by 0/)
    expect {2 / 0}.to raise_error(ZeroDivisionError)
    # try-catch - expected circumstance handling
    lambda { throw :room_is_full }.should throw_symbol(:room_is_full)
    # predicates
    nil.should be_nil #call nil.nil?
    [].should be_empty # calls [].empty?
    [1,2,3].should_not be_empty # calls [1,2,3].empty
    # convert anything that begins with have_ to a predicate on the target object beginning with has_
    {:id => 1}.has_key?(:id).should == true
    # can be written as
    {:id => 1}.should have_key(:id) # calls {:id => 1}.has_key?(:id)
    # collections
    obj = {}
    def obj.numbers
    [1,2,3,4]
    end
    obj.should have(4).numbers # calls obj.numbers.length
    [1,2,3,4].should have(4).items # 'items' is 'reserved' to say "ensure number of items on the collection"
    [1,2,3,4].should be_any {|n| n % 2 == 0} # [1,2,3,4].any? {|n| n %% 2 == 0}.should be_true
    "stringy".should have(7).charaters # same as items, just syntactic sugar
    [1,2,3,4].should have_exactly(24).items # same as 'have'
    obj.should have_at_least(3).numbers
    end
    end # built-in matchers
    context "custom matchers" do
    # TODO: describe multiple ways
    #define class
    class SimilarTo
    # mandatory - link to the object under test
    def initialize(it)
    # object under test
    @it = it
    end
    # mandatory - check the positive condition
    def matches?(that)
    @that = that # save to use it in messages
    @that.to_s.downcase.should == @it.to_s.downcase
    end
    # optional - opoosite to mathch?
    def does_not_matche?(that)
    result = !matches?(that)
    @that, @it = @it, @that # swap for negative condition or additionally cusomtize messages
    result # don't forget to return
    end
    # mandatory
    def failure_message_for_should
    "expected #{@it} to be similar to #{@that}"
    end
    # optional
    def failure_message_for_should_not
    "expected #{@it} to be different from #{@that}"
    end
    #optional
    def description
    "#{@it} should be similar to #{@that}"
    end
    end
    #define method on example (see set-up to incude in all examples)
    def similar_to(that)
    SimilarTo.new(that)
    end
    end # custom matchers
    context "macros" do
    module ControllerMacros
    def should_render(template)
    it "should render the #{template} template" do
    do_request
    response.should render_template(template)
    end
    end
    expect {
    # not changing
    }.to_not change { count }
    count = 1
    expect {
    count = 3
    }.to change { count }.to(3)
    count = 1
    expect {
    count = 3
    }.to change { count }from(1).to(3)
    # raise-rescue - exception handling
    expect {2 / 0}.to raise_error("divided by 0")
    expect {2 / 0}.to raise_error(/by 0/)
    expect {2 / 0}.to raise_error(ZeroDivisionError)
    # try-catch - expected circumstance handling
    lambda { throw :room_is_full }.should throw_symbol(:room_is_full)
    # predicates
    nil.should be_nil #call nil.nil?
    [].should be_empty # calls [].empty?
    [1,2,3].should_not be_empty # calls [1,2,3].empty
    # convert anything that begins with have_ to a predicate on the target object beginning with has_
    {:id => 1}.has_key?(:id).should == true
    # can be written as
    {:id => 1}.should have_key(:id) # calls {:id => 1}.has_key?(:id)
    # collections
    obj = {}
    def obj.numbers
    [1,2,3,4]
    end
    obj.should have(4).numbers # calls obj.numbers.length
    [1,2,3,4].should have(4).items # 'items' is 'reserved' to say "ensure number of items on the collection"
    [1,2,3,4].should be_any {|n| n % 2 == 0} # [1,2,3,4].any? {|n| n %% 2 == 0}.should be_true
    "stringy".should have(7).charaters # same as items, just syntactic sugar
    [1,2,3,4].should have_exactly(24).items # same as 'have'
    obj.should have_at_least(3).numbers
    end
    end # built-in matchers
    context "custom matchers" do
    # TODO: describe multiple ways
    #define class
    class SimilarTo
    # mandatory - link to the object under test
    def initialize(it)
    # object under test
    @it = it
    end
    # mandatory - check the positive condition
    def matches?(that)
    @that = that # save to use it in messages
    @that.to_s.downcase.should == @it.to_s.downcase
    end
    # optional - opoosite to mathch?
    def does_not_matche?(that)
    result = !matches?(that)
    @that, @it = @it, @that # swap for negative condition or additionally cusomtize messages
    result # don't forget to return
    end
    # mandatory
    def failure_message_for_should
    "expected #{@it} to be similar to #{@that}"
    end
    # optional
    def failure_message_for_should_not
    "expected #{@it} to be different from #{@that}"
    end
    #optional
    def description
    "#{@it} should be similar to #{@that}"
    end
    end
    #define method on example (see set-up to incude in all examples)
    def similar_to(that)
    SimilarTo.new(that)
    end
    end # custom matchers
    context "macros" do
    module ControllerMacros
    def should_render(template)
    it "should render the #{template} template" do
    do_request
    response.should render_template(template)
    end
    end

    def should_assign(hash)
    variable_name = hash.keys.first
    model, method = hash[variable_name]
    model_access_method = [model, method].join('.')
    it "should assign @#{variable_name} => #{model_access_method}" do
    expected = "the value returned by #{model_access_method}"
    model.should_receive(method).and_return(expected)
    do_request
    assigns[variable_name].should == expected
    end
    end
    def should_assign(hash)
    variable_name = hash.keys.first
    model, method = hash[variable_name]
    model_access_method = [model, method].join('.')
    it "should assign @#{variable_name} => #{model_access_method}" do
    expected = "the value returned by #{model_access_method}"
    model.should_receive(method).and_return(expected)
    do_request
    assigns[variable_name].should == expected
    end
    end

    def get(action)
    define_method :do_request do
    get action
    end
    yield
    end
    end
    def get(action)
    define_method :do_request do
    get action
    end
    yield
    end
    end

    RSpec.configure do |config|
    config.use_transactional_fixtures = true
    config.use_instantiated_fixtures = false
    config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
    config.extend(ControllerMacros, :type => :controller)
    end
    end # macros
    RSpec.configure do |config|
    config.use_transactional_fixtures = true
    config.use_instantiated_fixtures = false
    config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
    config.extend(ControllerMacros, :type => :controller)
    end
    end # macros
    end # module
  3. @dnagir dnagir revised this gist Dec 14, 2010. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -293,6 +293,10 @@ def greater_than(floor)
    expect {
    count = 3
    }.to change { count }.by(2)

    expect {
    # not changing
    }.to_not change { count }

    count = 1
    expect {
  4. @dnagir dnagir revised this gist Nov 11, 2010. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -330,6 +330,7 @@ def obj.numbers

    obj.should have(4).numbers # calls obj.numbers.length
    [1,2,3,4].should have(4).items # 'items' is 'reserved' to say "ensure number of items on the collection"
    [1,2,3,4].should be_any {|n| n % 2 == 0} # [1,2,3,4].any? {|n| n %% 2 == 0}.should be_true
    "stringy".should have(7).charaters # same as items, just syntactic sugar
    [1,2,3,4].should have_exactly(24).items # same as 'have'
    obj.should have_at_least(3).numbers
  5. @dnagir dnagir revised this gist Nov 10, 2010. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -58,6 +58,10 @@ module Player
    # no need to use 'subject.should', use 'should'
    specify { should have(10).items } # same as below
    specify { subject.should have(10).items }


    # similar to specify { subject.track_number.should == 1}
    its(:track_number) { should == 1 }

    context "specs set-up" do
    # we can run setup before each examle, or all of them
  6. @dnagir dnagir revised this gist Nov 9, 2010. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -269,6 +269,7 @@ def greater_than(floor)
    5.should be > 3
    5.should be <= 5
    (1.251).should be_close(1.25, 0.005)
    (1.251).should be_within(0.005).of 1.25 # >= RSpec 2.1
    "reg exp".should =~ /exp/
    [1,2].should include(1)
    1.should respond_to(:to_s)
  7. @dnagir dnagir created this gist Nov 5, 2010.
    421 changes: 421 additions & 0 deletions rspec-syntax-cheat-sheet.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,421 @@
    # RSpec 2.0 syntax Cheet Sheet by http://ApproachE.com

    # defining spec within a module will automatically pick Player::MovieList as a 'subject' (see below)
    module Player
    describe MovieList, "with optional description" do

    it "is pending example, so that you can write ones quickly"

    it "is already working example that we want to suspend from failing temporarily" do
    pending("working on another feature that temporarily breaks this one")
    # actual test code is here, will never be reached
    end

    it "is pending when failing" do
    pending "This will be marked as pending when the block will fail, otherwise (on success) will fail telling 'Why am I pending if I pass?'" do
    1.should == 2 # will mark example as pending
    2.should == 2 # will fail asking to remove pending status of example
    end
    end

    # this will automatically generate name of the example based on the expectations inside it ~ 'it' with no description
    specify { [1,2,3].should have(3).items }

    #any helper methods, before/after, modules etc declared in the outer group are available in the inner group.
    describe "outer" do
    before(:each) { puts "first" }
    describe "inner" do
    before(:each) { puts "second" }
    it { puts "third"}
    after(:each) { puts "fourth" }
    end
    after(:each) { puts "fifth" }
    end

    # 'describe' and 'context' are equivalent
    # I prefer to use 'context' for defining an 'environment'
    context "when first created" do
    it "is empty" do
    movie_list = MovieList.new
    movie_list.should be_empty
    end
    end

    # I prefer to use 'describe' for nouns, verbs; defining a nested set of specifications
    describe "forward" do
    it "should jump to a next movie" do
    next_movie = MovieList.new(2).forward
    next_movie.track_number.should == 2
    end
    end
    end

    it "will have default subject that corresponds to the instance of first parameter in 'describe'" do
    subject.class.should be == MovieList
    end
    # unless subject is set explicitly
    subject { MovieList.new(10) } # approximately similar to 'before(:each)'
    # no need to use 'subject.should', use 'should'
    specify { should have(10).items } # same as below
    specify { subject.should have(10).items }

    context "specs set-up" do
    # we can run setup before each examle, or all of them
    before(:each) do
    @new_on_each_example = YourObject.new
    end
    before do
    @new_on_each_spec_less_verbose = YourObject.new
    end
    before(:all) do
    # Avoid using it as it will bring the 'shared state' into unit tests
    @same_instance_for_all_examples_within_the_context = YourObject.new
    end
    it "can access attributes defined in 'before'" do
    @new_on_each_example.should_not be_nil
    @same_instance_for_all_examples_within_the_context.should_not be_nil
    end

    # cleanup code can be run the same way using 'after' instead of 'before'
    # Avoid using 'after'
    # we can wrap examples: before + after + manual handling
    # In most cases 'before' + 'after' will work better.
    around do |example|
    DB.transaction { example.run }
    # should handle errors manually, so do not do something like:
    # DB.start_transaction
    # example.run
    # DB.rollback_transaction
    end
    it "should run within a transaction" do
    MovieList.new.save!
    end

    let(:new_on_each_example) { ObjectPerExample.new }
    it "can use method defined by 'let'" do
    new_on_each_example.should_not be_nil
    # the object is memoized, so
    new_on_each_example.should == new_on_each_example
    end

    # defining helper methods within context may be more useful than setup
    def forward(times) do
    list = MoviewList.new(10)
    list.forward(times).track_number
    end
    it "can use it multiple times" do
    forward(1).should == 1
    forward(2).should == 2
    forward(10).should == 1
    end

    # using 'yield' with helper methods
    def given_thing_with(options)
    yield Thing.new do |thing|
    thing.set_status(options[:status])
    end
    end
    it "should do something when ok" do
    given_thing_with(:status => 'ok') do |thing|
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    end
    end


    # helpers can come from modules
    module Helpers
    def shared_help
    [1,2,3]
    end
    end
    include Helpers
    it "can use helpers from Module" do
    shared_help.should == [1,2,3]
    end
    # or this module can be included for ALL example groups automatically during configuration:
    # RSpec.configure do |config|
    # config.include Helpers
    # end
    end


    context "built-it stubbing, faking, mocking" do
    it "can stub" do
    source = double('source')
    source.stub(:fetch) { [1,2,3,4,5] }
    source.stub(:fetch_from).and_return([1,2]) # other way
    MovieList.stub(:find).and_return(MovieList.new) # stub class method

    implementing = double('source')
    implementing.stub(:fetch) do |count|
    count == 5 ? [1,2,3] : [4,5,6,7] # provide stub logic here, easy to use for Fakes
    end
    # easily stub chains of calls
    Blog.stub_chain(:posts, :published, :recent).and_return([1,2,3])
    Blog.posts.published.recent.should == [1,2,3]
    end
    it "can ignore non-expected method calls (NullObject pattern)" do
    source = double('source', :url => 'http://example.com').as_null_object
    source.any_method_call_onwill_return_nil.should be_nil
    # the source mock object will record the 'any_method_call_onwill_return_nil' message internally though
    end
    it "can set expectations" do
    source = double('source')
    # arguments
    source.should_receive(:fetch).with(10, "abc").and_return([1,2]) # expecting arguments (10, "abc") otherwise failing
    source.should_receive(:fetch).with(instance_of(Integer), "abc").and_return([1,2]) # don't care about 1st argument as long as it is Integer
    source.should_receive(:fetch).with(10, anything).and_return([1,2]) # don't care about 2nd argument at all
    source.should_receive(:fetch).with(any_args) # same as not using 'with' - don't care about arguments
    source.should_receive(:fetch).with(no_args) # 0 arguments, otherwise fail
    source.should_receive(:fetch).with(hash_including(:count => 10, :url => 'abc')) # arg should be Hash with all the values mentioned
    source.should_receive(:fetch).with(hash_not_including(:timeout => 5)) # arg should be Hash that contains no ':timout=>5'
    source.should_receive(:fetch).with(anything, /example/) # 2nd arg shuold match RegEx
    source.should_receive(:fetch).and_return([1], [1,2], [1,2,3]) # 1st call - [1], 2nd - [1,2], 3rd - [1,2,3], 4th - [1] and so on ...
    # expectation overrides stub
    source.stub(:fetch).and_return([1,2]) # will return [1,2] when called
    source.should_recieve(:fetch).and_return([3,4]) # prev been overriden and will return [3,4]
    # raising/throwing
    source.should_receive(:fetch).and_raise # raise Exception
    source.should_receive(:fetch).and_raise(ZeroDivisionError) # raise ZeroDivisionError
    source.should_receive(:fetch).and_raise(Exception.new('instance of aexception')) # raise given exception
    source.should_receive(:fetch).and_throw(:zero) # thro :zero
    # order
    source.should_receive(:first).ordered # order matters in relation to others marked as ordered
    source.should_receive(:dosnt_matter) # don't care about order as long as it is called
    source.should_receive(:second).ordered # must be called after 'first'
    # order is not enforced across different objects:
    double('a').should_receive(:a).ordered # not related to the next one
    double('b').should_receive(:b).ordered # not related to the prev one
    # how many times?
    source.should_recieve(:fetch).exactly(1)times
    source.should_recieve(:fetch).at_most(5)times
    source.should_recieve(:fetch).at_least(2)times
    source.should_recieve(:fetch).twice
    source.should_recieve(:fetch).once
    # negative expectations
    source.should_recieve(:fetch).never
    source.should_recieve(:fetch).exactly(0)times
    source.should_not_recieve(:fetch)


    list = MovieList.new(source)
    # if source.fetch has not been called, then example will fail
    end

    context "custom expectations" do
    # define custom expection class somewhere
    class GreaterThanMatcher
    def initialize(expected)
    @expected = expected
    end
    def description
    # will generate proper failure message and name of the example
    "a number greater than #{@expected}"
    end
    def ==(actual)
    # this will be called from
    actual > @expected
    end
    end

    # add this method to the RSpec (see set-up for global configuration)
    def greater_than(floor)
    GreaterThanMatcher.new(floor)
    end

    it "can be used in expectations" do
    subject.should_recieve(:forward).with(greater_than 3)
    subject.forward(5)
    end
    end # custom matchers
    end # mocking





    # set of same examples shared accross multiple specs
    # shared_examples_for should be in a separate file and defined outside of 'describe'/'context'
    shared_examples_for "any pizza" do
    it "tastes really good" do
    @pizza.should taste_really_good
    end
    end

    # to include the shared examples, into example groups:
    # it will assume @pizza instance variable is available here
    it_behaves_like "any pizza"

    context 'defining examples dynamically - everybody knows that :)' do
    {2 => 4, 3 => 6, 10 => 20}.each do |input, output|
    it "#{input} * 2 should be equal to #{output}" do
    (input * 2).should == output
    # will produce examples:
    # - 2 * 2 should be equal to 4
    # - 3 * 2 should be equal to 6
    # - 10 * 2 should be equal to 20
    end
    end
    end


    context "matchers" do
    it "shows built-in matchers" do
    # TODO: describe ===, eql, equal
    1.should == 1
    1.should_not == 2 # NOT 1.should != 2
    1.should_not equal(2) # same as above
    1.should_not == 2
    5.should be > 3
    5.should be <= 5
    (1.251).should be_close(1.25, 0.005)
    "reg exp".should =~ /exp/
    [1,2].should include(1)
    1.should respond_to(:to_s)

    true.should be_true
    0.should be_true
    "this".should be_true

    lambda { Object.new.explodde! }.should raise_error(NameError)

    # nothing fits
    5.should satisfy { |it| it == 5 }
    end

    it "shows cool things" do
    count = 1
    expect {
    count = 3
    }.to change { count }.by(2)

    count = 1
    expect {
    count = 3
    }.to change { count }.to(3)

    count = 1
    expect {
    count = 3
    }.to change { count }from(1).to(3)

    # raise-rescue - exception handling
    expect {2 / 0}.to raise_error("divided by 0")
    expect {2 / 0}.to raise_error(/by 0/)
    expect {2 / 0}.to raise_error(ZeroDivisionError)

    # try-catch - expected circumstance handling
    lambda { throw :room_is_full }.should throw_symbol(:room_is_full)

    # predicates
    nil.should be_nil #call nil.nil?
    [].should be_empty # calls [].empty?
    [1,2,3].should_not be_empty # calls [1,2,3].empty

    # convert anything that begins with have_ to a predicate on the target object beginning with has_
    {:id => 1}.has_key?(:id).should == true
    # can be written as
    {:id => 1}.should have_key(:id) # calls {:id => 1}.has_key?(:id)

    # collections
    obj = {}
    def obj.numbers
    [1,2,3,4]
    end

    obj.should have(4).numbers # calls obj.numbers.length
    [1,2,3,4].should have(4).items # 'items' is 'reserved' to say "ensure number of items on the collection"
    "stringy".should have(7).charaters # same as items, just syntactic sugar
    [1,2,3,4].should have_exactly(24).items # same as 'have'
    obj.should have_at_least(3).numbers


    end
    end # built-in matchers





    context "custom matchers" do
    # TODO: describe multiple ways

    #define class
    class SimilarTo
    # mandatory - link to the object under test
    def initialize(it)
    # object under test
    @it = it
    end
    # mandatory - check the positive condition
    def matches?(that)
    @that = that # save to use it in messages
    @that.to_s.downcase.should == @it.to_s.downcase
    end
    # optional - opoosite to mathch?
    def does_not_matche?(that)
    result = !matches?(that)
    @that, @it = @it, @that # swap for negative condition or additionally cusomtize messages
    result # don't forget to return
    end
    # mandatory
    def failure_message_for_should
    "expected #{@it} to be similar to #{@that}"
    end
    # optional
    def failure_message_for_should_not
    "expected #{@it} to be different from #{@that}"
    end
    #optional
    def description
    "#{@it} should be similar to #{@that}"
    end
    end

    #define method on example (see set-up to incude in all examples)
    def similar_to(that)
    SimilarTo.new(that)
    end
    end # custom matchers




    context "macros" do
    module ControllerMacros
    def should_render(template)
    it "should render the #{template} template" do
    do_request
    response.should render_template(template)
    end
    end

    def should_assign(hash)
    variable_name = hash.keys.first
    model, method = hash[variable_name]
    model_access_method = [model, method].join('.')
    it "should assign @#{variable_name} => #{model_access_method}" do
    expected = "the value returned by #{model_access_method}"
    model.should_receive(method).and_return(expected)
    do_request
    assigns[variable_name].should == expected
    end
    end

    def get(action)
    define_method :do_request do
    get action
    end
    yield
    end
    end

    RSpec.configure do |config|
    config.use_transactional_fixtures = true
    config.use_instantiated_fixtures = false
    config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
    config.extend(ControllerMacros, :type => :controller)
    end
    end # macros

    end # module