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