SlideShare a Scribd company logo
1 of 70
Download to read offline
RSpec 3
Contents
1. Changes from v2.14 to v3.y.z
2. Better Specs reviewed
Changes from
v2.14 to v3.y.z
Expect to not
‘should’ anymore
Changes
● New syntax does not use “monkey patching”
● Examples are based on “expectations” over objects
</>
What is it about?
# ‘should’ is “replaced” by ‘expect’
#
it ‘stores 5 in its attribute’ do
expect(subject.attribute).to eq 5
end
</>
In one line
# One-liner syntax changes accordingly
#
it { should eq 5 }
# Is written like...
#
it { is_expected.to eq 5 }
Migrating
● We can migrate our current specs to the new syntax
using github.com/yujinakayama/transpec
● In 3.1.z, there’s still a mechanism to work with the old
syntax
Don’t stub. Allow.
Changes
● New syntax to stub methods
● Also a new syntax to set expectations on method
calls
</>
How to stub
# Old
instance.stub(:method)
instance.stub(:method).with(<arguments>)
instance.stub(:method).with(<arguments>).and_return(<something>)
# New
allow(instance).to receive(:method)
allow(instance).to receive(:method).with(<arguments>)
allow(instance).to receive(:method).with(<arguments>)...
</>
stub on any instance
# Old
Object.any_instance.stub(:method)
Object.any_instance.stub(:method).with(<arguments>)
Object.any_instance.stub(:method).with(<arguments>).and_...
# New
allow_any_instance_of(Object).to receive(:method)
allow_any_instance_of(Object).to receive(:method).with...
allow_any_instance_of(Object).to receive(:method).with...
</>
stub chain
# Old
instance.stub_chain(:method_a, :method_b)
# New
allow(instance).to receive_message_chain(:method_a, :method_b)
</>
Method expectations
# Old
instance.should_receive(:method)
instance.should_receive(:method).with(<arguments>)
# New
expect(instance).to receive(:method)
expect(instance).to receive(:method).with(<arguments>)
</>
...on any instance
# Old
Object.any_instance.should_receive(:method)
Object.any_instance.should_receive(:method).with(<arguments>)
# New
expect_any_instance_of(Object).to receive(:method)
expect_any_instance_of(Object).to receive(:method).with...
Tools of trade
Skip it...
</>
Many ways to skip an example
# Common way
#
it ‘stores 5 in its attribute’, skip: true do
# Giving a reason for the output
#
it ‘stores 5 in its attribute’, skip: ‘reason’ do
# Shortcut
#
skip ‘stores 5 in its attribute’ do
...or leave it pending
Pending should make sense
● When an example inside a pending block passes,
RSpec will show an error
● This enforces that all pending blocks are pending for
a good reason
Matchmakers
Cha-cha-chain
</>
Chaining
# You can chain multiple ‘matchers’
#
expect(subject.attribute).
to start_with(‘hello’).and end_with(‘world’)
expect(subject.attribute).
to start_with(‘hello’).or start_with(‘goodbye’)
</>
The cooler way
# You can chain multiple ‘matchers’
#
expect(subject.attribute).
to start_with(‘hello’) & end_with(‘world’)
expect(subject.attribute).
to start_with(‘hello’) | start_with(‘goodbye’)
Structural matching
</>
A matcher for structures
# ‘match’ can validate Hash and Array object structures
#
let(:structure) { {key: :value, other_key: :other_value} }
expect(structure).
to match({key: :value, other_key: :other_value})
# Still works for strings and regexps as before
=~?
</>
Match arrays
# =~ does not work anymore as an array’s content matcher
# Now
expect(ary).to contain_exactly(1, 2, 3)
# Also in its explicit version
expect(ary).to match_array([1, 2, 3])
be_yourself
</>
Cambios en el ser
# ‘be_true’ becomes ‘be_truthy’
expect(true).to be_truthy
# ‘be_false’ becomes ‘be_falsey’ or ‘be_falsy’
expect(false).to be_falsey
expect(false).to be_falsy
# Having better semantics like in...
expect(nil).to be_falsey # instead of ‘be_false’
</>
Cambios en el ser
expect(nil).to be_false # Fails
expect(nil).to be_falsey # Passes
expect(‘hello world’).to be_true # Fails
expect(‘hello world’).to be_truthy # Passes
What’s gone
is kind of gone
The fired matchers
● its
github.com/rspec/rspec-its
● have, have_at_least, have_at_most
github.com/rspec/rspec-collection_matchers
Better Specs reviewed
Put some context
</>
Why, oh lord, why?
it ‘stores 5 in its attribute if attribute b is 6 and
attribute c is 7’ do
subject.attribute_b = 6
subject.attribute_c = 7
expect(subject.attribute).to eq 5
end
</>
Why not just...?
context ‘when attribute b is 6’ do
# ...
context ‘and attribute c is 7’ do
# ...
it ‘stores 5 in its attribute’ do
expect(subject.attribute).to eq 5
end
Analysis
● We can find good reasons not to do this:
○ It’s more code
○ It’s cumbersome
○ I’m just a lazy dog
● RSpec is about documentation.
● Documentation takes time.
● Good documentation takes even more time.
Isolation
VS
Combination
</>
This is not always a bad thing
it 'sets the attribute' do
subject.very_expensive_loading
expect(subject.attribute).to be_kind_of(Fixnum)
expect(subject.attribute).to eq(5)
end
</>
...but sometimes it’s unnecessary
it 'stores a fixnum in its attribute' do
expect(subject.attribute).to be_kind_of(Fixnum)
end
it 'its attribute’s fixnum is 5' do
expect(subject.attribute).to eq(5)
end
The right method
VS
The right result
</>
¿What should we test for?
it 'sets the attribute to 5' do
expect(subject).to receive(:=).with(5) # Dramatization
subject.set_attribute(5)
end
# Instead of
it 'sets the attribute to 5' do
subject.set_attribute(5)
expect(subject.attribute).to eq 5
end
Analysis
● Not always unnecessary.
● When it’s an expensive operations like the ones that
require access to an outside service, there’s no need
to test for its results. (Assume it’s already tested)
● Don’t be scared to raise the coverage of the same
method.
Change the subject
</>
Change the subject when you can
it 'returns an array’ do
expect(subject.method).to be_kind_of(Array)
end
it 'returns an array that includes ’foo’' do
expect(subject.method).to include(:foo)
end
it 'returns an array with something else' do
# ...
</>
Change the subject when you can
describe '#method’s return value' do
subject { instance.method }
it 'is an array’ do
expect(subject).to be_kind_of(Array)
end
it 'includes ’foo’' do
expect(subject).to include(:foo)
end
Let it be
</>
¡¡¡!!!
before do
@some_value = :foo
@some_other_value = :boo
@yet_some_other_value = :cmon_bro
@again_and_again = :you_are_killing_me
end
</>
And its little brother
it 'does something’ do
value_a = :foo
value_b = :boo
value_c = :cmon_bro
value_d = :you_are_killing_me
expect(instance.
method(value_a, value_b, value_c, value_d)).
to_not raise_error
end
</>
A relief in sight
let(:value_a) { :foo }
let(:value_b) { :boo }
let(:value_c) { :cmon_bro }
let(:value_d) { :you_are_killing_me }
it 'does something’ do
expect(instance.
method(value_a, value_b, value_c, value_d)).
to_not raise_error
end
Analysis
● Reuse of variables (DRY)
● Lazy loading
● Readability (Good documentation)
Avoid creating
a monster
</>
Don’t get excited about create
let(:model) { create(:model) }
# ORLY?
</>
Don’t get excited about create
let(:model) { build(:model) }
Analysis
● create stores in the database.
● I mean, it stores in the database.
● Do we really need to persist?
● build is new without save
● The bad thing is that we have to run callbacks
manually or setting up our Factory to do so
● Is that bad, anyway?
Stub when you have to
</>
Look what a pretty request
# Let’s pretend ‘instance.call_api’ is a very expensive call
it 'parses the api response’ do
expect(subject.parser(instance.call_api)).
to be_kind_of(Hash)
end
</>
Look what a pretty request
before do
allow(instance).to receive(:call_api).
and_return(<valid response from api>)
end
it 'parses the api response’ do
expect(subject.parser(instance.call_api)).
to be_kind_of(Hash)
end
Learn to share
</>
Inherited behavior
class Foo < Bar
# …
describe Foo do
it ‘serves drinks’
it ‘does whatever a foo does’
</>
Inherited behavior
class Foo < Bar
# …
shared_examples_for Bar do
it ‘serves drinks’
end
describe Foo do
it_behaves_like Bar
it ‘does whatever a foo does’
end
Analysis
● Reuse of examples (DRY).
● Consistent behavior across all subclasses.
● The idea is to only verify what’s inherited; we don’t
want to test private stuff.
Agree to disagree
David Heinemeier Hansson, creator of Ruby on Rails
David Heinemeier Hansson, creator of Ruby on Rails
David Heinemeier Hansson, creator of Ruby on Rails
David Heinemeier Hansson, creator of Ruby on Rails
myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3
betterspecs.org
rubyinside.com/dhh-offended-by-rspec-debate-4610.html
Sources
La fin

More Related Content

What's hot

Zero to Testing in JavaScript
Zero to Testing in JavaScriptZero to Testing in JavaScript
Zero to Testing in JavaScript
pamselle
 

What's hot (20)

Automated testing with RSpec
Automated testing with RSpecAutomated testing with RSpec
Automated testing with RSpec
 
Rspec API Documentation
Rspec API DocumentationRspec API Documentation
Rspec API Documentation
 
TDD, BDD, RSpec
TDD, BDD, RSpecTDD, BDD, RSpec
TDD, BDD, RSpec
 
Introduction to testing in Rails
Introduction to testing in RailsIntroduction to testing in Rails
Introduction to testing in Rails
 
TDD with phpspec2
TDD with phpspec2TDD with phpspec2
TDD with phpspec2
 
Clean Code
Clean CodeClean Code
Clean Code
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
 
RSpec User Stories
RSpec User StoriesRSpec User Stories
RSpec User Stories
 
Introduction to Python decorators
Introduction to Python decoratorsIntroduction to Python decorators
Introduction to Python decorators
 
RSpec
RSpecRSpec
RSpec
 
Create a web-app with Cgi Appplication
Create a web-app with Cgi AppplicationCreate a web-app with Cgi Appplication
Create a web-app with Cgi Appplication
 
2019-08-23 API contract testing with Dredd
2019-08-23 API contract testing with Dredd2019-08-23 API contract testing with Dredd
2019-08-23 API contract testing with Dredd
 
Testing JS with Jasmine
Testing JS with JasmineTesting JS with Jasmine
Testing JS with Jasmine
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Excellent
ExcellentExcellent
Excellent
 
Zero to Testing in JavaScript
Zero to Testing in JavaScriptZero to Testing in JavaScript
Zero to Testing in JavaScript
 
Practical Ext JS Debugging
Practical Ext JS DebuggingPractical Ext JS Debugging
Practical Ext JS Debugging
 
Rspec
RspecRspec
Rspec
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
 
Write codeforhumans
Write codeforhumansWrite codeforhumans
Write codeforhumans
 

Similar to RSpec 3: The new, the old, the good

Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web framework
taggg
 

Similar to RSpec 3: The new, the old, the good (20)

Introduction to unit testing
Introduction to unit testingIntroduction to unit testing
Introduction to unit testing
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
Karate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter ThomasKarate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter Thomas
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
 
C++11: Rvalue References, Move Semantics, Perfect Forwarding
C++11: Rvalue References, Move Semantics, Perfect ForwardingC++11: Rvalue References, Move Semantics, Perfect Forwarding
C++11: Rvalue References, Move Semantics, Perfect Forwarding
 
JavaScript / Web Engineering / Web Development / html + css + js/presentation
JavaScript / Web Engineering / Web Development / html + css + js/presentationJavaScript / Web Engineering / Web Development / html + css + js/presentation
JavaScript / Web Engineering / Web Development / html + css + js/presentation
 
Good Coding Practices with JavaScript
Good Coding Practices with JavaScriptGood Coding Practices with JavaScript
Good Coding Practices with JavaScript
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
mod_rewrite
mod_rewritemod_rewrite
mod_rewrite
 
Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web framework
 
Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013Rspec and Capybara Intro Tutorial at RailsConf 2013
Rspec and Capybara Intro Tutorial at RailsConf 2013
 
A linguagem de programação Ruby - Robson "Duda" Sejan Soares Dornelles
A linguagem de programação Ruby - Robson "Duda" Sejan Soares DornellesA linguagem de programação Ruby - Robson "Duda" Sejan Soares Dornelles
A linguagem de programação Ruby - Robson "Duda" Sejan Soares Dornelles
 
Ruby Programming Language
Ruby Programming LanguageRuby Programming Language
Ruby Programming Language
 
Rspec
RspecRspec
Rspec
 
Rails and security
Rails and securityRails and security
Rails and security
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
 
Ruby on rails rspec
Ruby on rails rspecRuby on rails rspec
Ruby on rails rspec
 

Recently uploaded

Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
amitlee9823
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
dharasingh5698
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
dollysharma2066
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
dharasingh5698
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 

Recently uploaded (20)

Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
Call Girls Pimpri Chinchwad Call Me 7737669865 Budget Friendly No Advance Boo...
 
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
 
Block diagram reduction techniques in control systems.ppt
Block diagram reduction techniques in control systems.pptBlock diagram reduction techniques in control systems.ppt
Block diagram reduction techniques in control systems.ppt
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
 
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
 
Thermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - VThermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - V
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
 
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...Booking open Available Pune Call Girls Pargaon  6297143586 Call Hot Indian Gi...
Booking open Available Pune Call Girls Pargaon 6297143586 Call Hot Indian Gi...
 
Online banking management system project.pdf
Online banking management system project.pdfOnline banking management system project.pdf
Online banking management system project.pdf
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
chapter 5.pptx: drainage and irrigation engineering
chapter 5.pptx: drainage and irrigation engineeringchapter 5.pptx: drainage and irrigation engineering
chapter 5.pptx: drainage and irrigation engineering
 
NFPA 5000 2024 standard .
NFPA 5000 2024 standard                                  .NFPA 5000 2024 standard                                  .
NFPA 5000 2024 standard .
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 

RSpec 3: The new, the old, the good

  • 2. Contents 1. Changes from v2.14 to v3.y.z 2. Better Specs reviewed
  • 5. Changes ● New syntax does not use “monkey patching” ● Examples are based on “expectations” over objects
  • 6. </> What is it about? # ‘should’ is “replaced” by ‘expect’ # it ‘stores 5 in its attribute’ do expect(subject.attribute).to eq 5 end
  • 7. </> In one line # One-liner syntax changes accordingly # it { should eq 5 } # Is written like... # it { is_expected.to eq 5 }
  • 8. Migrating ● We can migrate our current specs to the new syntax using github.com/yujinakayama/transpec ● In 3.1.z, there’s still a mechanism to work with the old syntax
  • 10. Changes ● New syntax to stub methods ● Also a new syntax to set expectations on method calls
  • 11. </> How to stub # Old instance.stub(:method) instance.stub(:method).with(<arguments>) instance.stub(:method).with(<arguments>).and_return(<something>) # New allow(instance).to receive(:method) allow(instance).to receive(:method).with(<arguments>) allow(instance).to receive(:method).with(<arguments>)...
  • 12. </> stub on any instance # Old Object.any_instance.stub(:method) Object.any_instance.stub(:method).with(<arguments>) Object.any_instance.stub(:method).with(<arguments>).and_... # New allow_any_instance_of(Object).to receive(:method) allow_any_instance_of(Object).to receive(:method).with... allow_any_instance_of(Object).to receive(:method).with...
  • 13. </> stub chain # Old instance.stub_chain(:method_a, :method_b) # New allow(instance).to receive_message_chain(:method_a, :method_b)
  • 14. </> Method expectations # Old instance.should_receive(:method) instance.should_receive(:method).with(<arguments>) # New expect(instance).to receive(:method) expect(instance).to receive(:method).with(<arguments>)
  • 15. </> ...on any instance # Old Object.any_instance.should_receive(:method) Object.any_instance.should_receive(:method).with(<arguments>) # New expect_any_instance_of(Object).to receive(:method) expect_any_instance_of(Object).to receive(:method).with...
  • 18. </> Many ways to skip an example # Common way # it ‘stores 5 in its attribute’, skip: true do # Giving a reason for the output # it ‘stores 5 in its attribute’, skip: ‘reason’ do # Shortcut # skip ‘stores 5 in its attribute’ do
  • 19. ...or leave it pending
  • 20. Pending should make sense ● When an example inside a pending block passes, RSpec will show an error ● This enforces that all pending blocks are pending for a good reason
  • 23. </> Chaining # You can chain multiple ‘matchers’ # expect(subject.attribute). to start_with(‘hello’).and end_with(‘world’) expect(subject.attribute). to start_with(‘hello’).or start_with(‘goodbye’)
  • 24. </> The cooler way # You can chain multiple ‘matchers’ # expect(subject.attribute). to start_with(‘hello’) & end_with(‘world’) expect(subject.attribute). to start_with(‘hello’) | start_with(‘goodbye’)
  • 26. </> A matcher for structures # ‘match’ can validate Hash and Array object structures # let(:structure) { {key: :value, other_key: :other_value} } expect(structure). to match({key: :value, other_key: :other_value}) # Still works for strings and regexps as before
  • 27. =~?
  • 28. </> Match arrays # =~ does not work anymore as an array’s content matcher # Now expect(ary).to contain_exactly(1, 2, 3) # Also in its explicit version expect(ary).to match_array([1, 2, 3])
  • 30. </> Cambios en el ser # ‘be_true’ becomes ‘be_truthy’ expect(true).to be_truthy # ‘be_false’ becomes ‘be_falsey’ or ‘be_falsy’ expect(false).to be_falsey expect(false).to be_falsy # Having better semantics like in... expect(nil).to be_falsey # instead of ‘be_false’
  • 31. </> Cambios en el ser expect(nil).to be_false # Fails expect(nil).to be_falsey # Passes expect(‘hello world’).to be_true # Fails expect(‘hello world’).to be_truthy # Passes
  • 33. The fired matchers ● its github.com/rspec/rspec-its ● have, have_at_least, have_at_most github.com/rspec/rspec-collection_matchers
  • 36. </> Why, oh lord, why? it ‘stores 5 in its attribute if attribute b is 6 and attribute c is 7’ do subject.attribute_b = 6 subject.attribute_c = 7 expect(subject.attribute).to eq 5 end
  • 37. </> Why not just...? context ‘when attribute b is 6’ do # ... context ‘and attribute c is 7’ do # ... it ‘stores 5 in its attribute’ do expect(subject.attribute).to eq 5 end
  • 38. Analysis ● We can find good reasons not to do this: ○ It’s more code ○ It’s cumbersome ○ I’m just a lazy dog ● RSpec is about documentation. ● Documentation takes time. ● Good documentation takes even more time.
  • 40. </> This is not always a bad thing it 'sets the attribute' do subject.very_expensive_loading expect(subject.attribute).to be_kind_of(Fixnum) expect(subject.attribute).to eq(5) end
  • 41. </> ...but sometimes it’s unnecessary it 'stores a fixnum in its attribute' do expect(subject.attribute).to be_kind_of(Fixnum) end it 'its attribute’s fixnum is 5' do expect(subject.attribute).to eq(5) end
  • 42. The right method VS The right result
  • 43. </> ¿What should we test for? it 'sets the attribute to 5' do expect(subject).to receive(:=).with(5) # Dramatization subject.set_attribute(5) end # Instead of it 'sets the attribute to 5' do subject.set_attribute(5) expect(subject.attribute).to eq 5 end
  • 44. Analysis ● Not always unnecessary. ● When it’s an expensive operations like the ones that require access to an outside service, there’s no need to test for its results. (Assume it’s already tested) ● Don’t be scared to raise the coverage of the same method.
  • 46. </> Change the subject when you can it 'returns an array’ do expect(subject.method).to be_kind_of(Array) end it 'returns an array that includes ’foo’' do expect(subject.method).to include(:foo) end it 'returns an array with something else' do # ...
  • 47. </> Change the subject when you can describe '#method’s return value' do subject { instance.method } it 'is an array’ do expect(subject).to be_kind_of(Array) end it 'includes ’foo’' do expect(subject).to include(:foo) end
  • 49. </> ¡¡¡!!! before do @some_value = :foo @some_other_value = :boo @yet_some_other_value = :cmon_bro @again_and_again = :you_are_killing_me end
  • 50. </> And its little brother it 'does something’ do value_a = :foo value_b = :boo value_c = :cmon_bro value_d = :you_are_killing_me expect(instance. method(value_a, value_b, value_c, value_d)). to_not raise_error end
  • 51. </> A relief in sight let(:value_a) { :foo } let(:value_b) { :boo } let(:value_c) { :cmon_bro } let(:value_d) { :you_are_killing_me } it 'does something’ do expect(instance. method(value_a, value_b, value_c, value_d)). to_not raise_error end
  • 52. Analysis ● Reuse of variables (DRY) ● Lazy loading ● Readability (Good documentation)
  • 54. </> Don’t get excited about create let(:model) { create(:model) } # ORLY?
  • 55. </> Don’t get excited about create let(:model) { build(:model) }
  • 56. Analysis ● create stores in the database. ● I mean, it stores in the database. ● Do we really need to persist? ● build is new without save ● The bad thing is that we have to run callbacks manually or setting up our Factory to do so ● Is that bad, anyway?
  • 57. Stub when you have to
  • 58. </> Look what a pretty request # Let’s pretend ‘instance.call_api’ is a very expensive call it 'parses the api response’ do expect(subject.parser(instance.call_api)). to be_kind_of(Hash) end
  • 59. </> Look what a pretty request before do allow(instance).to receive(:call_api). and_return(<valid response from api>) end it 'parses the api response’ do expect(subject.parser(instance.call_api)). to be_kind_of(Hash) end
  • 61. </> Inherited behavior class Foo < Bar # … describe Foo do it ‘serves drinks’ it ‘does whatever a foo does’
  • 62. </> Inherited behavior class Foo < Bar # … shared_examples_for Bar do it ‘serves drinks’ end describe Foo do it_behaves_like Bar it ‘does whatever a foo does’ end
  • 63. Analysis ● Reuse of examples (DRY). ● Consistent behavior across all subclasses. ● The idea is to only verify what’s inherited; we don’t want to test private stuff.
  • 65. David Heinemeier Hansson, creator of Ruby on Rails
  • 66. David Heinemeier Hansson, creator of Ruby on Rails
  • 67. David Heinemeier Hansson, creator of Ruby on Rails
  • 68. David Heinemeier Hansson, creator of Ruby on Rails