Rspec and Rails

  • 1,685 views
Uploaded on

This is a presentation which shows how to unit test with rspec, factory girl in a rails project

This is a presentation which shows how to unit test with rspec, factory girl in a rails project

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,685
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
66
Comments
0
Likes
5

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Transcript

  • 1. Rspec and Rails Abraham Kuri
  • 2. Table of Contents01 Rails setup02 Expectations & Matchers03 Shoulda & DRY Specs04 Context & Describe blocks05 Before block06 Stub & Mock07 Where to go next?
  • 3. Rails Setup
  • 4. Rails Setup
  • 5. Rails Setup$ rails new <app_name> --skip-test-unit
  • 6. Rails Setup$ rails new <app_name> --skip-test-unitGemfile:group :test, :development do gem rspec-rails gem "factory_girl_rails" gem ffakerend
  • 7. Rails Setup$ rails new <app_name> --skip-test-unitGemfile:group :test, :development do gem rspec-rails gem "factory_girl_rails" gem ffakerend
  • 8. Rails Setup$ rails new <app_name> --skip-test-unitGemfile:group :test, :development do gem rspec-rails gem "factory_girl_rails" gem ffakerend
  • 9. Rails Setup$ rails new <app_name> --skip-test-unitGemfile:group :test, :development do gem rspec-rails gem "factory_girl_rails" gem ffakerend$ bundle install
  • 10. Rails Setup$ rails new <app_name> --skip-test-unitGemfile:group :test, :development do gem rspec-rails gem "factory_girl_rails" gem ffakerend$ bundle install$ rails g rspec:install
  • 11. Expectations & Matchers‣ user_spec.rb
  • 12. Expectations & Matchers‣ user_spec.rb
  • 13. Expectations & Matchers‣ user_spec.rbdescribe 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 endend
  • 14. Expectations & Matchers‣ user_spec.rbdescribe 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 endend
  • 15. Expectations & Matchers‣ user_spec.rbdescribe 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 endend
  • 16. Expectations & Matchers‣ user_spec.rbdescribe 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 endend
  • 17. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher
  • 18. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher
  • 19. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher
  • 20. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher
  • 21. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 22. Expectations & Matchers‣ user_spec.rbdescribe 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 endend matcher describe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil } end
  • 23. Other matchers
  • 24. Other matchersuser.name.should == "Abraham"user.friends.should > 3user.alive.should == trueuser.alive.should_not == falseuser.girlfriend.should == niluser.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 matchersuser.name.should == "Abraham"user.friends.should > 3user.alive.should == true user.alive.should be_trueuser.alive.should_not == falseuser.girlfriend.should == niluser.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 matchersuser.name.should == "Abraham"user.friends.should > 3user.alive.should == true user.alive.should be_trueuser.alive.should_not == false user.alive.should_not be_falseuser.girlfriend.should == niluser.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 matchersuser.name.should == "Abraham"user.friends.should > 3user.alive.should == true user.alive.should be_trueuser.alive.should_not == false user.alive.should_not be_falseuser.girlfriend.should == nil user.alive.should be_niluser.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 rescuedescribe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil }end
  • 31. Shoulda to the rescuedescribe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil }end
  • 32. Shoulda to the rescuedescribe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil }endit { should validate_presence_of(:name) }
  • 33. Shoulda to the rescuedescribe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil }endit { should validate_presence_of(:name) }it { should validate_uniqueness_of(:email) }it { should have_many(:friends).through(:friendship) }
  • 34. Shoulda to the rescuedescribe User do let(:user) { FactoryGirl.create(:user) } subject { user } its(:name) { should_not be_nil }endit { should validate_presence_of(:name) }it { should validate_uniqueness_of(:email) }it { should have_many(:friends).through(:friendship) }it { should belong_to(:user)}
  • 35. Context & Describe Blocks
  • 36. Context & Describe Blocksdescribe User do describe when sleep do it snores describe with a soft pillow do it still snores it have good dreams end endend
  • 37. Context & Describe Blocksdescribe User do describe when sleep do it snores describe with a soft pillow do it still snores it have good dreams end endend
  • 38. Context & Describe Blocksdescribe User do describe when sleep do it snores describe with a soft pillow do it still snores it have good dreams end endend Use context instead of describe
  • 39. Context & Describe Blocksdescribe User do describe when sleep do it snores describe with a soft pillow do it still snores it have good dreams end endend Use context instead of describedescribe User do context when sleep do it snores context with a soft pillow do it still snores it have good dreams end endend
  • 40. Context & Describe Blocksdescribe User do describe when sleep do it snores describe with a soft pillow do it still snores it have good dreams end endend Use context instead of describedescribe User do context when sleep do it snores context with a soft pillow do it still snores it have good dreams end endend
  • 41. Before block
  • 42. Before blockdescribe 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 endend
  • 43. Before blockdescribe 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 endend
  • 44. Before blockdescribe 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 endend Let’s be more DRY
  • 45. Before blockdescribe 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 endend Let’s be more DRYdescribe friends names do
  • 46. Before blockdescribe 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 endend Let’s be more DRYdescribe friends names do context when has friends do
  • 47. Before blockdescribe 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 endend Let’s be more DRYdescribe friends names do context when has friends do before do
  • 48. Before blockdescribe 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 endend Let’s be more DRYdescribe friends names do context when has friends do before do 3.times { user.friends << FactoryGirl.create(:friend) }
  • 49. Before blockdescribe 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 endend Let’s be more DRYdescribe friends names do context when has friends do before do 3.times { user.friends << FactoryGirl.create(:friend) } end
  • 50. Before blockdescribe 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 endend Let’s be more DRYdescribe 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 blockdescribe 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 endend Let’s be more DRYdescribe 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 blockdescribe 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 endend Let’s be more DRYdescribe 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 blockdescribe 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 endend Let’s be more DRYdescribe 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) } endend
  • 54. Before blockdescribe 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 endend Let’s be more DRYdescribe 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) } endend
  • 55. Before blockdescribe 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 endend Let’s be more DRYdescribe 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) } endend Much better
  • 56. Stubs & Mocking
  • 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
  • 59. Stub it out
  • 60. Stub it outapp/models/user.rbclass User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" endend
  • 61. Stub it out User feed_stomachapp/models/user.rbclass User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" endend
  • 62. Stub it out User feed_stomachapp/models/user.rbclass User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" endend
  • 63. Stub it out User Stomach feed_stomach def feed(*args) return nil endapp/models/user.rbclass User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" endend
  • 64. Stub it out User Stomach feed_stomach def feed(*args) return nil end user.stomach.stub(:feed_stomach)app/models/user.rbclass User < ActiveRecord::Base has_one :stomach def feed_stomach stomach.feed(self) self.status = "full" endend
  • 65. Complete spec
  • 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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" enddescribe 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 endend We need to test that feed is called
  • 79. Mocha flavor
  • 80. Mocha flavor/app/models/user.rbdef 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.rbit calls the Facebook Graph to get friends do FbGraph::User.should_receive(:me).with(user.token) .and_return(["1", "45", "987"]) user.fb_friends_idsend 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.rbit calls the Facebook Graph to get friends do FbGraph::User.should_receive(:me).with(user.token) .and_return(["1", "45", "987"]) user.fb_friends_idsend 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