SlideShare a Scribd company logo
Rspec and Rails
    Abraham Kuri
Table of Contents
01   Rails setup
02   Expectations & Matchers
03   Shoulda & DRY Specs
04   Context & Describe blocks
05   Before block
06   Stub & Mock
07   Where to go next?
Rails Setup
Rails Setup
Rails Setup

$ rails new <app_name> --skip-test-unit
Rails Setup

$ rails new <app_name> --skip-test-unit

Gemfile:

group   :test, :development do
  gem   'rspec-rails'
  gem   "factory_girl_rails"
  gem   'ffaker'
end
Rails Setup

$ rails new <app_name> --skip-test-unit

Gemfile:

group   :test, :development do
  gem   'rspec-rails'
  gem   "factory_girl_rails"
  gem   'ffaker'
end
Rails Setup

$ rails new <app_name> --skip-test-unit

Gemfile:

group   :test, :development do
  gem   'rspec-rails'
  gem   "factory_girl_rails"
  gem   'ffaker'
end
Rails Setup

$ rails new <app_name> --skip-test-unit

Gemfile:

group   :test, :development do
  gem   'rspec-rails'
  gem   "factory_girl_rails"
  gem   'ffaker'
end




$ bundle install
Rails Setup

$ rails new <app_name> --skip-test-unit

Gemfile:

group   :test, :development do
  gem   'rspec-rails'
  gem   "factory_girl_rails"
  gem   'ffaker'
end




$ bundle install
$ rails g rspec:install
Expectations & Matchers
‣ user_spec.rb
Expectations & Matchers
‣ user_spec.rb
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil
    user.should_not == nil
  end
end
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil
    user.should_not == nil
  end
end
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher



 describe User do
   let(:user) { FactoryGirl.create(:user) }
   subject { user }

   its(:name) { should_not be_nil }
 end
Expectations & Matchers
‣ user_spec.rb
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  it 'should not be valid without a name' do
    user.name = nil     modifier
    user.should_not == nil
  end
end                         matcher



 describe User do
   let(:user) { FactoryGirl.create(:user) }
   subject { user }

   its(:name) { should_not be_nil }
 end
Other matchers
Other matchers
user.name.should == "Abraham"

user.friends.should > 3

user.alive.should == true


user.alive.should_not == false


user.girlfriend.should == nil


user.should be_alive

                                          have(n)
user.friends.should include(other_user)   have_at_least(n)
                                          have_at_most(n)
user.should have(2).arms
Other matchers
user.name.should == "Abraham"

user.friends.should > 3

user.alive.should == true
                                 user.alive.should be_true

user.alive.should_not == false


user.girlfriend.should == nil


user.should be_alive

                                               have(n)
user.friends.should include(other_user)        have_at_least(n)
                                               have_at_most(n)
user.should have(2).arms
Other matchers
user.name.should == "Abraham"

user.friends.should > 3

user.alive.should == true
                                 user.alive.should be_true

user.alive.should_not == false
                                 user.alive.should_not be_false

user.girlfriend.should == nil


user.should be_alive

                                               have(n)
user.friends.should include(other_user)        have_at_least(n)
                                               have_at_most(n)
user.should have(2).arms
Other matchers
user.name.should == "Abraham"

user.friends.should > 3

user.alive.should == true
                                 user.alive.should be_true

user.alive.should_not == false
                                 user.alive.should_not be_false

user.girlfriend.should == nil
                                 user.alive.should be_nil

user.should be_alive

                                               have(n)
user.friends.should include(other_user)        have_at_least(n)
                                               have_at_most(n)
user.should have(2).arms
Shoulda to the rescue
Shoulda to the rescue
Shoulda to the rescue
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  its(:name) { should_not be_nil }

end
Shoulda to the rescue
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  its(:name) { should_not be_nil }

end
Shoulda to the rescue
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  its(:name) { should_not be_nil }

end


it { should validate_presence_of(:name) }
Shoulda to the rescue
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  its(:name) { should_not be_nil }

end


it { should validate_presence_of(:name) }

it { should validate_uniqueness_of(:email) }

it { should have_many(:friends).through(:friendship) }
Shoulda to the rescue
describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  its(:name) { should_not be_nil }

end


it { should validate_presence_of(:name) }

it { should validate_uniqueness_of(:email) }

it { should have_many(:friends).through(:friendship) }


it { should belong_to(:user)}
Context & Describe Blocks
Context & Describe Blocks
describe User do
  describe 'when sleep' do
    it 'snores'
    describe 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end
Context & Describe Blocks
describe User do
  describe 'when sleep' do
    it 'snores'
    describe 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end
Context & Describe Blocks
describe User do
  describe 'when sleep' do
    it 'snores'
    describe 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end          Use context instead       of describe
Context & Describe Blocks
describe User do
  describe 'when sleep' do
    it 'snores'
    describe 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end          Use context instead       of describe


describe User do
  context 'when sleep' do
    it 'snores'
    context 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end
Context & Describe Blocks
describe User do
  describe 'when sleep' do
    it 'snores'
    describe 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end          Use context instead       of describe


describe User do
  context 'when sleep' do
    it 'snores'
    context 'with a soft pillow' do
      it 'still snores'
      it 'have good dreams'
    end
  end
end
Before block
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
    its(:friend_names) { should == user.friends.map(&:name) }
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
    its(:friend_names) { should == user.friends.map(&:name) }
  end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
    its(:friend_names) { should == user.friends.map(&:name) }
  end
end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
    its(:friend_names) { should == user.friends.map(&:name) }
  end
end
Before block
describe 'friends names' do
  context 'when has friends' do
    it 'should have 3 friends' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.should have(3).friends
    end
    it 'should return friend names' do
      3.times { user.friends << FactoryGirl.create(:friend) }
      user.friend_names.should == user.friends.map(&:name)
    end
  end
end                                         Let’s be more DRY


describe 'friends names' do
  context 'when has friends' do
    before do
      3.times { user.friends << FactoryGirl.create(:friend) }
    end
    it { should have(3).friends }
    its(:friend_names) { should == user.friends.map(&:name) }
  end
end                                           Much better
Stubs & Mocking
Stubs & Mocking
‣ Stubs

 For replacing a method with code that
 return a specified result
Stubs & Mocking
‣ Stubs

  For replacing a method with code that
  return a specified result



‣ Mocks

 A stub with an expectations that the
 method gets called
Stub it out
Stub it out



app/models/user.rb
class User < ActiveRecord::Base
  has_one :stomach

  def feed_stomach
    stomach.feed(self)
    self.status = "full"
  end

end
Stub it out
        User
      feed_stomach




app/models/user.rb
class User < ActiveRecord::Base
  has_one :stomach

  def feed_stomach
    stomach.feed(self)
    self.status = "full"
  end

end
Stub it out
        User
      feed_stomach




app/models/user.rb
class User < ActiveRecord::Base
  has_one :stomach

  def feed_stomach
    stomach.feed(self)
    self.status = "full"
  end

end
Stub it out
        User                          Stomach
      feed_stomach                def feed(*args)
                                    return nil
                                  end




app/models/user.rb
class User < ActiveRecord::Base
  has_one :stomach

  def feed_stomach
    stomach.feed(self)
    self.status = "full"
  end

end
Stub it out
        User                          Stomach
      feed_stomach                def feed(*args)
                                    return nil
                                  end


                                                    user.stomach.stub(:feed_stomach)



app/models/user.rb
class User < ActiveRecord::Base
  has_one :stomach

  def feed_stomach
    stomach.feed(self)
    self.status = "full"
  end

end
Complete spec
Complete spec
                def feed_stomach
                  stomach.feed(self)
                  self.status = "full"
                end
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end




                  We need to test that feed is called
Complete spec
                                                   def feed_stomach
                                                     stomach.feed(self)
/spec/models/user_spec.rb                            self.status = "full"
                                                   end
describe User do




                   We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do
       user.stomach.stub(:feed)




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do
       user.stomach.stub(:feed)
       user.feed_stomach




                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do
       user.stomach.stub(:feed)
       user.feed_stomach
       user.status.should == "full"



                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do
       user.stomach.stub(:feed)
       user.feed_stomach
       user.status.should == "full"
     end

                  We need to test that feed is called
Complete spec
                                                  def feed_stomach
                                                    stomach.feed(self)
/spec/models/user_spec.rb                           self.status = "full"
                                                  end
describe User do
  let(:user) { FactoryGirl.create(:user) }

   describe '#feed_stomach' do
     it 'set the status to full' do
       user.stomach.stub(:feed)
       user.feed_stomach
       user.status.should == "full"
     end
   end
                  We need to test that feed is called
Complete spec
                                                def feed_stomach
                                                  stomach.feed(self)
/spec/models/user_spec.rb                         self.status = "full"
                                                end
describe User do
  let(:user) { FactoryGirl.create(:user) }

  describe '#feed_stomach' do
    it 'set the status to full' do
      user.stomach.stub(:feed)
      user.feed_stomach
      user.status.should == "full"
    end
  end
end             We need to test that feed is called
Mocha flavor
Mocha flavor
/app/models/user.rb

def fb_friends_ids
    user = FbGraph::User.me(self.token)
    user.friends.map { |o| o.raw_attributes[:id] }
end
Mocha flavor
/app/models/user.rb
                                              ["1", "45", "987"]
def fb_friends_ids
    user = FbGraph::User.me(self.token)
    user.friends.map { |o| o.raw_attributes[:id] }
end
Mocha flavor
/app/models/user.rb
                                              ["1", "45", "987"]
def fb_friends_ids
    user = FbGraph::User.me(self.token)
    user.friends.map { |o| o.raw_attributes[:id] }
end


/app/specs/user_spec.rb
Mocha flavor
/app/models/user.rb
                                              ["1", "45", "987"]
def fb_friends_ids
    user = FbGraph::User.me(self.token)
    user.friends.map { |o| o.raw_attributes[:id] }
end


/app/specs/user_spec.rb

it 'calls the Facebook Graph to get friends' do
  FbGraph::User.should_receive(:me).with(user.token)
  .and_return(["1", "45", "987"])
  user.fb_friends_ids
end

          stubs the method + expectation with correct
                            param
                                 return value
Mocha flavor
/app/models/user.rb
                                              ["1", "45", "987"]
def fb_friends_ids
    user = FbGraph::User.me(self.token)
    user.friends.map { |o| o.raw_attributes[:id] }
end


/app/specs/user_spec.rb

it 'calls the Facebook Graph to get friends' do
  FbGraph::User.should_receive(:me).with(user.token)
  .and_return(["1", "45", "987"])
  user.fb_friends_ids
end

          stubs the method + expectation with correct
                            param
                                 return value
Where to go next?
http://rspec.info/
 https://github.com/rspec/rspec
 https://github.com/thoughtbot/shoulda

 http://eggsonbread.com/2010/03/28/my-rspec-
 best-practices-and-tips/
 http://www.rubyinside.com/how-to-rails-3-and-
 rspec-2-4336.html
Rspec & Rails




   Abraham Kuri

More Related Content

PDF
PDF
Beyond the DOM: Sane Structure for JS Apps
PDF
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
PDF
Symfony2 and Doctrine2 Integration
PDF
Chris Holland "Leveraging Typed Exceptions for Cleaner Error Handling"
PPTX
Data binding в массы! (1.2)
PPT
Mocking Dependencies in PHPUnit
PDF
Anton Minashkin Dagger 2 light
Beyond the DOM: Sane Structure for JS Apps
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
Symfony2 and Doctrine2 Integration
Chris Holland "Leveraging Typed Exceptions for Cleaner Error Handling"
Data binding в массы! (1.2)
Mocking Dependencies in PHPUnit
Anton Minashkin Dagger 2 light

What's hot (20)

PDF
Regexes and-performance-testing
PDF
Simple Photo Processing and Web Display with Perl
PDF
Active Support Core Extensions (1)
PDF
"Coffee Script" in Brief
KEY
究極のコントローラを目指す
PPTX
I regret nothing
PDF
Magicke metody v Pythonu
PDF
A New Baseline for Front-End Devs
PDF
CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏
PDF
Introduction to Web Components
PPTX
Presentation1
PDF
RubyBarCamp “Полезные gems и plugins”
PDF
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
PDF
RxSwift 시작하기
PDF
購物車程式架構簡介
PPTX
Coding for Scale and Sanity
PDF
Serializing Value Objects-Ara Hacopian
PDF
Mulberry: A Mobile App Development Toolkit
PDF
Headless Js Testing
Regexes and-performance-testing
Simple Photo Processing and Web Display with Perl
Active Support Core Extensions (1)
"Coffee Script" in Brief
究極のコントローラを目指す
I regret nothing
Magicke metody v Pythonu
A New Baseline for Front-End Devs
CakePHPをさらにDRYにする、ドライケーキレシピ akiyan.com 秋田真宏
Introduction to Web Components
Presentation1
RubyBarCamp “Полезные gems и plugins”
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
RxSwift 시작하기
購物車程式架構簡介
Coding for Scale and Sanity
Serializing Value Objects-Ara Hacopian
Mulberry: A Mobile App Development Toolkit
Headless Js Testing
Ad

Similar to Rspec and Rails (20)

PDF
Factory Girl
PPTX
Factory girl
PDF
Automated testing with RSpec
PDF
Testing Ruby with Rspec (a beginner's guide)
KEY
あたかも自然言語を書くようにコーディングしてみる
PDF
RSpec best practice - avoid using before and let
PDF
R spec let there be tests
PDF
RSpec Quick Reference
PPT
Ruby on Rails testing with Rspec
PDF
RSpec 3: The new, the old, the good
KEY
Dsl
KEY
Intro To Advanced Ruby
KEY
Desarrollando aplicaciones web en minutos
PDF
Ruby 程式語言入門導覽
PDF
PDF
Ruby on rails rspec
PDF
All Objects are created .equal?
KEY
jRuby: The best of both worlds
PDF
From dot net_to_rails
PDF
Introduction to unit testing
Factory Girl
Factory girl
Automated testing with RSpec
Testing Ruby with Rspec (a beginner's guide)
あたかも自然言語を書くようにコーディングしてみる
RSpec best practice - avoid using before and let
R spec let there be tests
RSpec Quick Reference
Ruby on Rails testing with Rspec
RSpec 3: The new, the old, the good
Dsl
Intro To Advanced Ruby
Desarrollando aplicaciones web en minutos
Ruby 程式語言入門導覽
Ruby on rails rspec
All Objects are created .equal?
jRuby: The best of both worlds
From dot net_to_rails
Introduction to unit testing
Ad

More from Icalia Labs (16)

PDF
Building an Api the Right Way
PDF
Agile practices for management
PDF
Building something out of Nothing
PDF
Furatto tertulia
PDF
Simple but Useful Design Principles.
PDF
Your time saving front end workflow
PDF
Customer Experience Basics
PDF
Introduction to Swift programming language.
PDF
Time Hacks for Work
PDF
Culture in a team
PDF
Curso rails
PPTX
Presentacion vim
PPTX
Using github development process in your company
PDF
The Art of Pitching
PDF
Rails Best Practices
PDF
Introduccion meteor.js
Building an Api the Right Way
Agile practices for management
Building something out of Nothing
Furatto tertulia
Simple but Useful Design Principles.
Your time saving front end workflow
Customer Experience Basics
Introduction to Swift programming language.
Time Hacks for Work
Culture in a team
Curso rails
Presentacion vim
Using github development process in your company
The Art of Pitching
Rails Best Practices
Introduccion meteor.js

Recently uploaded (20)

PDF
cuic standard and advanced reporting.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Electronic commerce courselecture one. Pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Machine learning based COVID-19 study performance prediction
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Approach and Philosophy of On baking technology
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
NewMind AI Weekly Chronicles - August'25 Week I
cuic standard and advanced reporting.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
Electronic commerce courselecture one. Pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Machine learning based COVID-19 study performance prediction
The AUB Centre for AI in Media Proposal.docx
Review of recent advances in non-invasive hemoglobin estimation
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Unlocking AI with Model Context Protocol (MCP)
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Approach and Philosophy of On baking technology
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Spectral efficient network and resource selection model in 5G networks
Reach Out and Touch Someone: Haptics and Empathic Computing
NewMind AI Weekly Chronicles - August'25 Week I

Rspec and Rails

  • 1. Rspec and Rails Abraham Kuri
  • 2. Table of Contents 01 Rails setup 02 Expectations & Matchers 03 Shoulda & DRY Specs 04 Context & Describe blocks 05 Before block 06 Stub & Mock 07 Where to go next?
  • 5. Rails Setup $ rails new <app_name> --skip-test-unit
  • 6. Rails Setup $ rails new <app_name> --skip-test-unit Gemfile: group :test, :development do gem 'rspec-rails' gem "factory_girl_rails" gem 'ffaker' end
  • 7. Rails Setup $ rails new <app_name> --skip-test-unit Gemfile: group :test, :development do gem 'rspec-rails' gem "factory_girl_rails" gem 'ffaker' end
  • 8. Rails Setup $ rails new <app_name> --skip-test-unit Gemfile: group :test, :development do gem 'rspec-rails' gem "factory_girl_rails" gem 'ffaker' end
  • 9. Rails Setup $ rails new <app_name> --skip-test-unit Gemfile: group :test, :development do gem 'rspec-rails' gem "factory_girl_rails" gem 'ffaker' end $ bundle install
  • 10. Rails Setup $ rails new <app_name> --skip-test-unit Gemfile: group :test, :development do gem 'rspec-rails' gem "factory_girl_rails" gem 'ffaker' end $ bundle install $ rails g rspec:install
  • 13. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil user.should_not == nil end end
  • 14. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil user.should_not == nil end end
  • 15. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end
  • 16. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end
  • 17. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher
  • 18. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher
  • 19. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher
  • 20. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher
  • 21. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 22. Expectations & Matchers ‣ user_spec.rb describe User do let(:user) { FactoryGirl.create(:user) } subject { user } it 'should not be valid without a name' do user.name = nil modifier user.should_not == nil end end matcher describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 24. Other matchers user.name.should == "Abraham" user.friends.should > 3 user.alive.should == true user.alive.should_not == false user.girlfriend.should == nil user.should be_alive have(n) user.friends.should include(other_user) have_at_least(n) have_at_most(n) user.should have(2).arms
  • 25. Other matchers user.name.should == "Abraham" user.friends.should > 3 user.alive.should == true user.alive.should be_true user.alive.should_not == false user.girlfriend.should == nil user.should be_alive have(n) user.friends.should include(other_user) have_at_least(n) have_at_most(n) user.should have(2).arms
  • 26. Other matchers user.name.should == "Abraham" user.friends.should > 3 user.alive.should == true user.alive.should be_true user.alive.should_not == false user.alive.should_not be_false user.girlfriend.should == nil user.should be_alive have(n) user.friends.should include(other_user) have_at_least(n) have_at_most(n) user.should have(2).arms
  • 27. Other matchers user.name.should == "Abraham" user.friends.should > 3 user.alive.should == true user.alive.should be_true user.alive.should_not == false user.alive.should_not be_false user.girlfriend.should == nil user.alive.should be_nil user.should be_alive have(n) user.friends.should include(other_user) have_at_least(n) have_at_most(n) user.should have(2).arms
  • 28. Shoulda to the rescue
  • 29. Shoulda to the rescue
  • 30. Shoulda to the rescue describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 31. Shoulda to the rescue describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 32. Shoulda to the rescue describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end it { should validate_presence_of(:name) }
  • 33. Shoulda to the rescue describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end it { should validate_presence_of(:name) } it { should validate_uniqueness_of(:email) } it { should have_many(:friends).through(:friendship) }
  • 34. Shoulda to the rescue describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end it { should validate_presence_of(:name) } it { should validate_uniqueness_of(:email) } it { should have_many(:friends).through(:friendship) } it { should belong_to(:user)}
  • 36. Context & Describe Blocks describe User do describe 'when sleep' do it 'snores' describe 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end
  • 37. Context & Describe Blocks describe User do describe 'when sleep' do it 'snores' describe 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end
  • 38. Context & Describe Blocks describe User do describe 'when sleep' do it 'snores' describe 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end Use context instead of describe
  • 39. Context & Describe Blocks describe User do describe 'when sleep' do it 'snores' describe 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end Use context instead of describe describe User do context 'when sleep' do it 'snores' context 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end
  • 40. Context & Describe Blocks describe User do describe 'when sleep' do it 'snores' describe 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end Use context instead of describe describe User do context 'when sleep' do it 'snores' context 'with a soft pillow' do it 'still snores' it 'have good dreams' end end end
  • 42. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end
  • 43. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end
  • 44. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY
  • 45. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do
  • 46. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do
  • 47. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do
  • 48. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) }
  • 49. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end
  • 50. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends }
  • 51. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends } its(:friend_names) { should == user.friends.map(&:name) }
  • 52. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends } its(:friend_names) { should == user.friends.map(&:name) } end
  • 53. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends } its(:friend_names) { should == user.friends.map(&:name) } end end
  • 54. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends } its(:friend_names) { should == user.friends.map(&:name) } end end
  • 55. Before block describe 'friends names' do context 'when has friends' do it 'should have 3 friends' do 3.times { user.friends << FactoryGirl.create(:friend) } user.should have(3).friends end it 'should return friend names' do 3.times { user.friends << FactoryGirl.create(:friend) } user.friend_names.should == user.friends.map(&:name) end end end Let’s be more DRY describe 'friends names' do context 'when has friends' do before do 3.times { user.friends << FactoryGirl.create(:friend) } end it { should have(3).friends } its(:friend_names) { should == user.friends.map(&:name) } end end Much better
  • 57. Stubs & Mocking ‣ Stubs For replacing a method with code that return a specified result
  • 58. Stubs & Mocking ‣ Stubs For replacing a method with code that return a specified result ‣ Mocks A stub with an expectations that the method gets called
  • 60. Stub it out app/models/user.rb class User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" end end
  • 61. Stub it out User feed_stomach app/models/user.rb class User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" end end
  • 62. Stub it out User feed_stomach app/models/user.rb class User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" end end
  • 63. Stub it out User Stomach feed_stomach def feed(*args) return nil end app/models/user.rb class User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" end end
  • 64. Stub it out User Stomach feed_stomach def feed(*args) return nil end user.stomach.stub(:feed_stomach) app/models/user.rb class User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" end end
  • 66. Complete spec def feed_stomach stomach.feed(self) self.status = "full" end
  • 67. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end We need to test that feed is called
  • 68. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do We need to test that feed is called
  • 69. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } We need to test that feed is called
  • 70. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } We need to test that feed is called
  • 71. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do We need to test that feed is called
  • 72. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do We need to test that feed is called
  • 73. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) We need to test that feed is called
  • 74. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) user.feed_stomach We need to test that feed is called
  • 75. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) user.feed_stomach user.status.should == "full" We need to test that feed is called
  • 76. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) user.feed_stomach user.status.should == "full" end We need to test that feed is called
  • 77. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) user.feed_stomach user.status.should == "full" end end We need to test that feed is called
  • 78. Complete spec def feed_stomach stomach.feed(self) /spec/models/user_spec.rb self.status = "full" end describe User do let(:user) { FactoryGirl.create(:user) } describe '#feed_stomach' do it 'set the status to full' do user.stomach.stub(:feed) user.feed_stomach user.status.should == "full" end end end We need to test that feed is called
  • 80. Mocha flavor /app/models/user.rb def fb_friends_ids user = FbGraph::User.me(self.token) user.friends.map { |o| o.raw_attributes[:id] } end
  • 81. Mocha flavor /app/models/user.rb ["1", "45", "987"] def fb_friends_ids user = FbGraph::User.me(self.token) user.friends.map { |o| o.raw_attributes[:id] } end
  • 82. Mocha flavor /app/models/user.rb ["1", "45", "987"] def fb_friends_ids user = FbGraph::User.me(self.token) user.friends.map { |o| o.raw_attributes[:id] } end /app/specs/user_spec.rb
  • 83. Mocha flavor /app/models/user.rb ["1", "45", "987"] def fb_friends_ids user = FbGraph::User.me(self.token) user.friends.map { |o| o.raw_attributes[:id] } end /app/specs/user_spec.rb it 'calls the Facebook Graph to get friends' do FbGraph::User.should_receive(:me).with(user.token) .and_return(["1", "45", "987"]) user.fb_friends_ids end stubs the method + expectation with correct param return value
  • 84. Mocha flavor /app/models/user.rb ["1", "45", "987"] def fb_friends_ids user = FbGraph::User.me(self.token) user.friends.map { |o| o.raw_attributes[:id] } end /app/specs/user_spec.rb it 'calls the Facebook Graph to get friends' do FbGraph::User.should_receive(:me).with(user.token) .and_return(["1", "45", "987"]) user.fb_friends_ids end stubs the method + expectation with correct param return value
  • 85. Where to go next? http://rspec.info/ https://github.com/rspec/rspec https://github.com/thoughtbot/shoulda http://eggsonbread.com/2010/03/28/my-rspec- best-practices-and-tips/ http://www.rubyinside.com/how-to-rails-3-and- rspec-2-4336.html
  • 86. Rspec & Rails Abraham Kuri

Editor's Notes