Forked from luislee818/rspec_cheatsheet_for_zombies.markdown
Last active
August 29, 2015 14:27
-
-
Save hoasung01/f72b124a5c6075b94d21 to your computer and use it in GitHub Desktop.
Revisions
-
Dapeng Li created this gist
Mar 9, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,374 @@ ## Introduction ### Vocabulary ***Examples*** are decalred using the *it* method Assertions are called ***Expectations*** *should* and *should_not* are called ***Modifiers*** ***Matchers*** are the operators in the assertions (==, >, be_true, etc.) ### Install RSpec ```bash $ gem install rspec ... Successfully installed rspec-core Successfully installed rspec-expectations Successfully installed rspec-mocks Successfully installed rspec 4 gems installed ``` ### Initialize RSpec in your project directory ```bash $ rspec --init create spec/spec_helper.rb create .rspec ``` ### Initialize RSpec in Rails ```ruby group :development, :test do gem 'rspec-rails' end ``` ```bash $ bundle install ... Installing rspec-core Installing rspec-expectations Installing rspec-mocks Installing rspec Installing rspec-rails $ rails generate rspec:install create .rspec create spec/spec_helper.rb ``` ### Configuration in Rails spec/spec_helper.rb ```ruby # requires all helper files within spec/support Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} ... RSpec.configure do |config| # change the default mocking framework config.mock_with :mocha ... end ``` ### Running specs running all the '_spec.rb' files within /spec ```bash $ rspec ``` running a specific directory ```bash $ rspec spec/models ``` running a specific test ```bash $ rspec spec/models/zombie_spec.rb ``` running a specific line ```bash $ rspec spec/models/zombie_spec.rb:4 ``` Mark example as pending ```ruby it "is named Ash" xit "is named Ash" do ... end it "is named Ash" do pending ... end ``` ## Matchers ```ruby # basic zombie.name.should == 'Ash' zombie.alive.should be_false zombie.alive.should be_true  zombie.height.should > 5 zombie.brains.should be < 1 zombie.height.should >= 5 zombie.height.should < 5 zombie.height.should_not == 5 # predicate zombie.should class Zombie def hungry? true end end zombie.hungry?.should == true zombie.hungry?.should be_true zombie.should be_hungry # match zombie.name.should match(/Ash Clone \d/) # include zombie.tweets.should include(tweet1) # have # rather than zombie.weapons.count.should == 2 zombie.should have(2).weapons zombie.should have_at_least(2).weapons zombie.should have_at_most(2).weapons # change expect { zombie.save }.to change { Zombie.count }.by(1) expect { zombie.save }.to change { Zombie.count }.from(1).to(5) # raise_error expect { zombie.save! }.to raise_error( ActiveRecord::RecordInvalid ) # to # not_to # to_not # more matchers @zombie.should respond_to(:hungry?) @width.should be_within(0.1).of(33.3) @zombie.should exist @zombie.should satisfy { |zombie| zombie.hungry? } @hungry_zombie.should be_kind_of(Zombie) @status.should be_an_instance_of(String) ``` ## DRY Spec Implicit Subject ```ruby #describe Zombie do # it 'responds to name' do # zombie = Zombie.new # zombie.should respond_to(:name) # end # end # only works using describe with a class describe Zombie do it 'responds to name' do # subject = Zombie.new subject.should respond_to(:name) end end ``` Implicit Receiver ```ruby # describe Zombie do # it 'responds to name' do # subject.should respond_to(:name) # end # end describe Zombie do it 'responds to name' do should respond_to(:name) end end ``` it without name ```ruby # it 'responds to name' { should respond_to(:name) } it { should respond_to(:name) } ``` its ```ruby # it { subject.name.should == 'Ash' } its(:name) { should == 'Ash' } # more examples its(:name) { should == 'Ash' } its(:weapons) { should include(weapon) } its(:brain) { should be_nil } its('tweets.size') { should == 2 } ``` Nesting examples ```ruby # duplication!! describe Zombie do it 'craves brains when hungry' it 'with a veggie preference still craves brains when hungry' it 'with a veggie preference prefers vegan brains when hungry' end # duplication! describe Zombie do it 'craves brains when hungry' describe 'with a veggie preference' do it 'still craves brains when hungry' it 'prefers vegan brains when hungry' end end # better describe Zombie do describe 'when hungry' do it 'craves brains' describe 'with a veggie preference' do it 'still craves brains' it 'prefers vegan brains' end end end # even better with context instead of describe describe Zombie do context 'when hungry' do it 'craves brains' context 'with a veggie preference' do it 'still craves brains' it 'prefers vegan brains' end end end ``` Using Subject ```ruby # subject without name subject { Zombie.new(vegetarian: true, weapons: [axe]) } its(:weapons) { should include(axe) } # naming the subject let(:zombie) { Zombie.new(vegetarian: true, weapons: [axe]) } let(:axe) { Weapon.new(name: 'axe') } subject { zombie } # new subject syntax subject(:zombie) { Zombie.new(vegetarian: true, weapons: [axe]) }) let(:axe) { Weapon.new(name: 'axe') } # make sure let executes everytime (by default it's lazy evaluation) let!(:zombie) { Zombie.create } ``` Refactor specs using it/its/subject *before* ```ruby describe Zombie do it 'has no name' do @zombie = Zombie.create @zombie.name.should be_nil? end it 'craves brains' do @zombie = Zombie.create @zombie.should be_craving_brains end it 'should not be hungry after eating brains' do @zombie = Zombie.create @zombie.hungry.should be_true @zombie.eat(:brains) @zombie.hungry.should be_false end end ``` *after* ```ruby describe Zombie do let(:zombie) { Zombie.create } subject { zombie } its(:name) { should be_nil? } it { should be_craving_brains } it 'should not be hungry after eating brains' do expect { zombie.eat(:brains) }.to change { zombie.hungry }.from(true).to(false) end end ``` ## Hooks & Tags hooks ```ruby # run before each example before(:each) # run once before all before(:all) # run after each after(:each) # run after all after(:all) ``` ### *Shared examples (not included here)* ### *Metadata and filters (not included here)* ## Mocking & Stubbing ***Stub*** is for replacing a method with code that returns a specific result. ***Mock*** is a stub with an expectation that the method gets called. ### Stubbing ```ruby # stubbing zombie.weapon.stub(:slice) Zoogle.stub(:graveyard_locator).with(zombie.graveyard) .and_return({latitude: 2, longitude: 3}) # stubbing object loc = stub(latitude: 2, longitude: 3) # hash to object with methods Zoogle.stub(:graveyard_locator).returns(loc) ``` ### Mocking ```ruby # mocking zombie.weapon.should_receive(:slice) Zoogle.should_receive(:graveyard_locator).with(zombie.graveyard) Zoogle.should_receive(:graveyard_locator).with(zombie.graveyard) .and_return({latitude: 2, longitude: 3}) # more options target.should_receive(:function).once .twice .exactly(3).times .at_least(2).times .at_most(3).times .any_number_of_times  target.should_receive(:function).with(no_args()) .with(any_args()) .with("B", anything()) .with(3, kind_of(Numeric)) .with(/zombie ash/) ``` ## Custom Matchers (not included here)