SlideShare a Scribd company logo
1 of 75
Download to read offline
RSpec 3.0: Under the Covers
Achieving“Zero Monkey-Patching Mode”
Brian Gesiak
March 13th, 2014
Research Student, The University of Tokyo
@modocache
Today
• Monkey patching
• How does RSpec work?
• The rspec executable
• Loading spec files
• Example groups: describe and context
• RSpec 2.11: describe no longer added to every
Object
• Running examples (it blocks)
• Expectations
• RSpec 2.11: expect-based syntax removes need for
adding should to every Object
Monkey Patching
How to Do It and Why You Shouldn’t
class Array
def sum # Also defined in `activesupport`!
inject { |sum, x| sum + x }
end
end
!
expect([1, 2, 3].sum).to eq 6
Monkey Patching
How to Do It and Why You Shouldn’t
class Array
def sum # Also defined in `activesupport`!
inject { |sum, x| sum + x }
end
end
!
expect([1, 2, 3].sum).to eq 6
Monkey Patching
How to Do It and Why You Shouldn’t
class Array
def sum # Also defined in `activesupport`!
inject { |sum, x| sum + x }
end
end
!
expect([1, 2, 3].sum).to eq 6
Monkey patching can lead to cryptic errors
Monkey Patching Root Objects
Go Big or Go Home
class Object
def should
# ...
end
end
module Kernel
def describe
# ...
end
end
# Global method
describe
# All objects respond
# to method
Object.new.should
Monkey Patching Root Objects
Go Big or Go Home
class Object
def should
# ...
end
end
module Kernel
def describe
# ...
end
end
# Global method
describe
# All objects respond
# to method
Object.new.should
Monkey Patching Root Objects
Go Big or Go Home
class Object
def should
# ...
end
end
module Kernel
def describe
# ...
end
end
# Global method
describe
# All objects respond
# to method
Object.new.should
Monkey Patching Root Objects
Go Big or Go Home
class Object
def should
# ...
end
end
module Kernel
def describe
# ...
end
end
# Global method
describe
# All objects respond
# to method
Object.new.should
Monkey Patching Root Objects
Go Big or Go Home
class Object
def should
# ...
end
end
module Kernel
def describe
# ...
end
end
# Global method
describe
# All objects respond
# to method
Object.new.should
RSpec 3.0
Historically, RSpec has extensively used monkey
patching to create its readable syntax, adding
methods…to every object.
!
In the last few 2.x releases, we’ve worked towards
reducing the amount of monkey patching done by
RSpec.
Zero Monkey-Patching Mode
Myron Marston, RSpec Core Member
@myronmarston
RSpec 3.0
Achieving“Zero Monkey-Patching Mode”
$ rspec meetup_spec.rb
The rspec Executable
rspec-core/exe/rspec
#!/usr/bin/env ruby
!
require 'rspec/core'
RSpec::Core::Runner.invoke
The rspec Executable
rspec-core/exe/rspec
#!/usr/bin/env ruby
!
require 'rspec/core'
RSpec::Core::Runner.invoke
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Loading Spec Files
RSpec::Core::Configuration.load_spec_files
def load_spec_files
files_to_run.uniq.each { |f| load f }
@spec_files_loaded = true
end
Loading Spec Files
RSpec::Core::Configuration.load_spec_files
def load_spec_files
files_to_run.uniq.each { |f| load f }
@spec_files_loaded = true
end
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Where Does describe Come From?
RSpec::Core::DSL
def self.expose_example_group_alias(name)
example_group_aliases << name
!
(class << RSpec; self; end).
__send__(:define_method, name) # ...
!
expose_example_group_alias_globally(name) if
exposed_globally? # defines on Module
end
Where Does describe Come From?
RSpec::Core::DSL
def self.expose_example_group_alias(name)
example_group_aliases << name
!
(class << RSpec; self; end).
__send__(:define_method, name) # ...
!
expose_example_group_alias_globally(name) if
exposed_globally? # defines on Module
end
Where Does describe Come From?
RSpec::Core::DSL
def self.expose_example_group_alias(name)
example_group_aliases << name
!
(class << RSpec; self; end).
__send__(:define_method, name) # ...
!
expose_example_group_alias_globally(name) if
exposed_globally? # defines on Module
end
Where Does describe Come From?
RSpec::Core::DSL
def self.expose_example_group_alias(name)
example_group_aliases << name
!
(class << RSpec; self; end).
__send__(:define_method, name) # ...
!
expose_example_group_alias_globally(name) if
exposed_globally? # defines on Module
end
Disabling Module Monkey Patching
RSpec.configure do |config|
config.expose_dsl_globally = false
end
!
RSpec.describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
# ...
end
end
Only Top Level describe Blocks Are Affected
Disabling Module Monkey Patching
RSpec.configure do |config|
config.expose_dsl_globally = false
end
!
RSpec.describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
# ...
end
end
Only Top Level describe Blocks Are Affected
Disabling Module Monkey Patching
RSpec.configure do |config|
config.expose_dsl_globally = false
end
!
RSpec.describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
# ...
end
end
Only Top Level describe Blocks Are Affected
Disabling Module Monkey Patching
RSpec.configure do |config|
config.expose_dsl_globally = false
end
!
RSpec.describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
# ...
end
end
Only Top Level describe Blocks Are Affected
Opt-in as of RSpec 2.11
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Building Example Groups
describe TokyoRailsMeetup do
let(:meetup) { described_class.new }
describe '#start' do
context 'without a chef' do
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?)
.to be_true
end
end
end
end
Loading a Typical Spec File
Building Example Groups
Hierarchies of Example Groups and Examples
class ExampleGroup
def self.example_group(*args,
&example_group_block)
# ...
child = subclass(self,
args,
&example_group_block)
children << child
child
end
!
def self.examples
@examples ||= []
end
# ...
end
Building Example Groups
Hierarchies of Example Groups and Examples
class ExampleGroup
def self.example_group(*args,
&example_group_block)
# ...
child = subclass(self,
args,
&example_group_block)
children << child
child
end
!
def self.examples
@examples ||= []
end
# ...
end
Building Example Groups
Hierarchies of Example Groups and Examples
class ExampleGroup
def self.example_group(*args,
&example_group_block)
# ...
child = subclass(self,
args,
&example_group_block)
children << child
child
end
!
def self.examples
@examples ||= []
end
# ...
end
Building Example Groups
Hierarchies of Example Groups and Examples
class ExampleGroup
def self.example_group(*args,
&example_group_block)
# ...
child = subclass(self,
args,
&example_group_block)
children << child
child
end
!
def self.examples
@examples ||= []
end
# ...
end
Building Example Groups
Hierarchies of Example Groups and Examples
Running the Examples
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Running the Examples
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Running the Examples
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
RSpec::Core::CommandLine.run
Running the Examples
RSpec::Core::Example.run
def run(example_group_instance, reporter)
# ...
begin
run_before_each
@example_group_instance.
instance_exec(self, &@example_block)
rescue Exception => e
set_exception(e)
ensure
run_after_each
end
end
Running the Examples
RSpec::Core::Example.run
def run(example_group_instance, reporter)
# ...
begin
run_before_each
@example_group_instance.
instance_exec(self, &@example_block)
rescue Exception => e
set_exception(e)
ensure
run_after_each
end
end
Running the Examples
RSpec::Core::Example.run
def run(example_group_instance, reporter)
# ...
begin
run_before_each
@example_group_instance.
instance_exec(self, &@example_block)
rescue Exception => e
set_exception(e)
ensure
run_after_each
end
end
Running the Examples
RSpec::Core::Example.run
def run(example_group_instance, reporter)
# ...
begin
run_before_each
@example_group_instance.
instance_exec(self, &@example_block)
rescue Exception => e
set_exception(e)
ensure
run_after_each
end
end
Making Expectations
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
!
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?).to be_true
end
The Deprecated should Syntax
Making Expectations
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
!
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?).to be_true
end
The Deprecated should Syntax
How should is Monkey Patched
class Configuration
# ...
def syntax=(values)
if Array(values).include?(:expect)
Expectations::Syntax.enable_expect
else
Expectations::Syntax.disable_expect
end
!
if Array(values).include?(:should)
Expectations::Syntax.enable_should
else
Expectations::Syntax.disable_should
end
end
end
RSpec::Expectations::Configuration
How should is Monkey Patched
class Configuration
# ...
def syntax=(values)
if Array(values).include?(:expect)
Expectations::Syntax.enable_expect
else
Expectations::Syntax.disable_expect
end
!
if Array(values).include?(:should)
Expectations::Syntax.enable_should
else
Expectations::Syntax.disable_should
end
end
end
RSpec::Expectations::Configuration
How should is Monkey Patched
class Configuration
# ...
def syntax=(values)
if Array(values).include?(:expect)
Expectations::Syntax.enable_expect
else
Expectations::Syntax.disable_expect
end
!
if Array(values).include?(:should)
Expectations::Syntax.enable_should
else
Expectations::Syntax.disable_should
end
end
end
RSpec::Expectations::Configuration
How should is Monkey Patched
class Configuration
# ...
def syntax=(values)
if Array(values).include?(:expect)
Expectations::Syntax.enable_expect
else
Expectations::Syntax.disable_expect
end
!
if Array(values).include?(:should)
Expectations::Syntax.enable_should
else
Expectations::Syntax.disable_should
end
end
end
RSpec::Expectations::Configuration
How should is Monkey Patched
def enable_should(syntax_host=::Object.ancestors.last)
# ...
syntax_host.module_exec do
def should(matcher=nil, message=nil, &block)
# ...
end
!
def should_not(matcher=nil, message=nil, &block)
# ...
end
end
end
RSpec::Expectations::Syntax
How should is Monkey Patched
def enable_should(syntax_host=::Object.ancestors.last)
# ...
syntax_host.module_exec do
def should(matcher=nil, message=nil, &block)
# ...
end
!
def should_not(matcher=nil, message=nil, &block)
# ...
end
end
end
RSpec::Expectations::Syntax
How should is Monkey Patched
def enable_should(syntax_host=::Object.ancestors.last)
# ...
syntax_host.module_exec do
def should(matcher=nil, message=nil, &block)
# ...
end
!
def should_not(matcher=nil, message=nil, &block)
# ...
end
end
end
RSpec::Expectations::Syntax
Making Expectations
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
!
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?).to be_true
end
The New expect(…).to Syntax
Making Expectations
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
!
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?).to be_true
end
The New expect(…).to Syntax
Making Expectations
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
!
it 'gets everyone drunk' do
meetup.start
expect(meetup.everyone_wasted?).to be_true
end
The New expect(…).to Syntax
How expect is Implemented
def enable_expect(syntax_host=::RSpec::Matchers)
# ...
syntax_host.module_exec do
def expect(*target, &target_block)
# ...
end
end
end
RSpec::Expectations::Syntax
How expect is Implemented
def enable_expect(syntax_host=::RSpec::Matchers)
# ...
syntax_host.module_exec do
def expect(*target, &target_block)
# ...
end
end
end
RSpec::Expectations::Syntax
How expect is Implemented
def enable_expect(syntax_host=::RSpec::Matchers)
# ...
syntax_host.module_exec do
def expect(*target, &target_block)
# ...
end
end
end
RSpec::Expectations::Syntax
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
expect(meetup).to be_hoppin
Disabling should Monkey Patching
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
c.syntax = :expect
end
end
!
it 'is a grand old time' do
meetup.start
meetup.should be_hoppin
end
expect(meetup).to be_hoppin
should Emits Deprecation Warning as of RSpec 3.0
Bringing it All Together
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
Load the Specs & Build Example Groups, then Run
Bringing it All Together
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
Load the Specs & Build Example Groups, then Run
Bringing it All Together
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
Load the Specs & Build Example Groups, then Run
Bringing it All Together
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
Load the Specs & Build Example Groups, then Run
Bringing it All Together
class CommandLine
def run(err, out)
# ...
@configuration.load_spec_files
# ...
begin
@configuration.hooks.run(:before, :suite)
@world.ordered_example_groups.map {
|g| g.run(reporter) } # ...
ensure
@configuration.hooks.run(:after, :suite)
end
end
end
Load the Specs & Build Example Groups, then Run
Want to Learn More about RSpec?
• http://modocache.io/rspec-under-the-covers
• Expectations in RSpec 3.0
• RSpec Output Formatting
• Shared Examples in RSpec
!
• Follow me on Twitter and GitHub at @modocache
• First person to tweet me gets an Atom invite! #swag
!
• Myron Marston’s blog: http://myronmars.to/n/dev-blog

More Related Content

What's hot

AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and JasmineAngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasminefoxp2code
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSKnoldus Inc.
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle BuildAndres Almiray
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingMark Rickerby
 
Unit Testing in SilverStripe
Unit Testing in SilverStripeUnit Testing in SilverStripe
Unit Testing in SilverStripeIngo Schommer
 
Writing Custom Puppet Types and Providers to Manage Web-Based Applications
Writing Custom Puppet Types and Providers to Manage Web-Based ApplicationsWriting Custom Puppet Types and Providers to Manage Web-Based Applications
Writing Custom Puppet Types and Providers to Manage Web-Based ApplicationsTim Cinel
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Puppet
 
JavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and KarmaJavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and KarmaChristopher Bartling
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingLars Thorup
 
Intro to testing Javascript with jasmine
Intro to testing Javascript with jasmineIntro to testing Javascript with jasmine
Intro to testing Javascript with jasmineTimothy Oxley
 
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma Christopher Bartling
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to doPuppet
 
Angularjs - Unit testing introduction
Angularjs - Unit testing introductionAngularjs - Unit testing introduction
Angularjs - Unit testing introductionNir Kaufman
 
AngularJS Unit Testing
AngularJS Unit TestingAngularJS Unit Testing
AngularJS Unit TestingPrince Norin
 
Testing in AngularJS
Testing in AngularJSTesting in AngularJS
Testing in AngularJSPeter Drinnan
 

What's hot (20)

AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and JasmineAngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasmine
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
Getting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe TestingGetting to Grips with SilverStripe Testing
Getting to Grips with SilverStripe Testing
 
Unit Testing in SilverStripe
Unit Testing in SilverStripeUnit Testing in SilverStripe
Unit Testing in SilverStripe
 
Writing Custom Puppet Types and Providers to Manage Web-Based Applications
Writing Custom Puppet Types and Providers to Manage Web-Based ApplicationsWriting Custom Puppet Types and Providers to Manage Web-Based Applications
Writing Custom Puppet Types and Providers to Manage Web-Based Applications
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
 
Rest api with Python
Rest api with PythonRest api with Python
Rest api with Python
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
 
JavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and KarmaJavaScript TDD with Jasmine and Karma
JavaScript TDD with Jasmine and Karma
 
Advanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit TestingAdvanced Jasmine - Front-End JavaScript Unit Testing
Advanced Jasmine - Front-End JavaScript Unit Testing
 
Intro to testing Javascript with jasmine
Intro to testing Javascript with jasmineIntro to testing Javascript with jasmine
Intro to testing Javascript with jasmine
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma JavaScript Test-Driven Development with Jasmine 2.0 and Karma
JavaScript Test-Driven Development with Jasmine 2.0 and Karma
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to do
 
Angularjs - Unit testing introduction
Angularjs - Unit testing introductionAngularjs - Unit testing introduction
Angularjs - Unit testing introduction
 
AngularJS Unit Testing
AngularJS Unit TestingAngularJS Unit Testing
AngularJS Unit Testing
 
Testing in AngularJS
Testing in AngularJSTesting in AngularJS
Testing in AngularJS
 

Viewers also liked

Apple Templates Considered Harmful
Apple Templates Considered HarmfulApple Templates Considered Harmful
Apple Templates Considered HarmfulBrian Gesiak
 
Intel® Xeon® Phi Coprocessor High Performance Programming
Intel® Xeon® Phi Coprocessor High Performance ProgrammingIntel® Xeon® Phi Coprocessor High Performance Programming
Intel® Xeon® Phi Coprocessor High Performance ProgrammingBrian Gesiak
 
iOS UI Component API Design
iOS UI Component API DesigniOS UI Component API Design
iOS UI Component API DesignBrian Gesiak
 
iOS Behavior-Driven Development
iOS Behavior-Driven DevelopmentiOS Behavior-Driven Development
iOS Behavior-Driven DevelopmentBrian Gesiak
 
アップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられるアップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられるBrian Gesiak
 
iOSビヘイビア駆動開発
iOSビヘイビア駆動開発iOSビヘイビア駆動開発
iOSビヘイビア駆動開発Brian Gesiak
 
iOS UI Component API Design
iOS UI Component API DesigniOS UI Component API Design
iOS UI Component API DesignBrian Gesiak
 

Viewers also liked (7)

Apple Templates Considered Harmful
Apple Templates Considered HarmfulApple Templates Considered Harmful
Apple Templates Considered Harmful
 
Intel® Xeon® Phi Coprocessor High Performance Programming
Intel® Xeon® Phi Coprocessor High Performance ProgrammingIntel® Xeon® Phi Coprocessor High Performance Programming
Intel® Xeon® Phi Coprocessor High Performance Programming
 
iOS UI Component API Design
iOS UI Component API DesigniOS UI Component API Design
iOS UI Component API Design
 
iOS Behavior-Driven Development
iOS Behavior-Driven DevelopmentiOS Behavior-Driven Development
iOS Behavior-Driven Development
 
アップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられるアップルのテンプレートは有害と考えられる
アップルのテンプレートは有害と考えられる
 
iOSビヘイビア駆動開発
iOSビヘイビア駆動開発iOSビヘイビア駆動開発
iOSビヘイビア駆動開発
 
iOS UI Component API Design
iOS UI Component API DesigniOS UI Component API Design
iOS UI Component API Design
 

Similar to RSpec 3.0: Under the Covers

Better rspec 進擊的 RSpec
Better rspec 進擊的 RSpecBetter rspec 進擊的 RSpec
Better rspec 進擊的 RSpecLi Hsuan Hung
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends旻琦 潘
 
Tips to make your rspec specs awesome
Tips to make your rspec specs awesomeTips to make your rspec specs awesome
Tips to make your rspec specs awesomeSwati Jadhav
 
RSpec 1.x -> 2.0 の変更点
RSpec 1.x -> 2.0 の変更点RSpec 1.x -> 2.0 の変更点
RSpec 1.x -> 2.0 の変更点theworldinunion
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introductionKnoldus Inc.
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technologyppparthpatel123
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Coxlachie
 
What's new in Ruby 2.0
What's new in Ruby 2.0What's new in Ruby 2.0
What's new in Ruby 2.0Kartik Sahoo
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at WorkErin Dees
 
name name2 n
name name2 nname name2 n
name name2 ncallroom
 
name name2 n
name name2 nname name2 n
name name2 ncallroom
 
name name2 n
name name2 nname name2 n
name name2 ncallroom
 
name name2 n2.ppt
name name2 n2.pptname name2 n2.ppt
name name2 n2.pptcallroom
 

Similar to RSpec 3.0: Under the Covers (20)

Better rspec 進擊的 RSpec
Better rspec 進擊的 RSpecBetter rspec 進擊的 RSpec
Better rspec 進擊的 RSpec
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
Tips to make your rspec specs awesome
Tips to make your rspec specs awesomeTips to make your rspec specs awesome
Tips to make your rspec specs awesome
 
Language supports it
Language supports itLanguage supports it
Language supports it
 
RSpec 1.x -> 2.0 の変更点
RSpec 1.x -> 2.0 の変更点RSpec 1.x -> 2.0 の変更点
RSpec 1.x -> 2.0 の変更点
 
Scala lens: An introduction
Scala lens: An introductionScala lens: An introduction
Scala lens: An introduction
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technology
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Cox
 
What's new in Ruby 2.0
What's new in Ruby 2.0What's new in Ruby 2.0
What's new in Ruby 2.0
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
ppt7
ppt7ppt7
ppt7
 
ppt2
ppt2ppt2
ppt2
 
name name2 n
name name2 nname name2 n
name name2 n
 
test ppt
test ppttest ppt
test ppt
 
name name2 n
name name2 nname name2 n
name name2 n
 
ppt21
ppt21ppt21
ppt21
 
name name2 n
name name2 nname name2 n
name name2 n
 
ppt17
ppt17ppt17
ppt17
 
ppt30
ppt30ppt30
ppt30
 
name name2 n2.ppt
name name2 n2.pptname name2 n2.ppt
name name2 n2.ppt
 

Recently uploaded

AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Recently uploaded (20)

AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

RSpec 3.0: Under the Covers

  • 1. RSpec 3.0: Under the Covers Achieving“Zero Monkey-Patching Mode” Brian Gesiak March 13th, 2014 Research Student, The University of Tokyo @modocache
  • 2. Today • Monkey patching • How does RSpec work? • The rspec executable • Loading spec files • Example groups: describe and context • RSpec 2.11: describe no longer added to every Object • Running examples (it blocks) • Expectations • RSpec 2.11: expect-based syntax removes need for adding should to every Object
  • 3. Monkey Patching How to Do It and Why You Shouldn’t class Array def sum # Also defined in `activesupport`! inject { |sum, x| sum + x } end end ! expect([1, 2, 3].sum).to eq 6
  • 4. Monkey Patching How to Do It and Why You Shouldn’t class Array def sum # Also defined in `activesupport`! inject { |sum, x| sum + x } end end ! expect([1, 2, 3].sum).to eq 6
  • 5. Monkey Patching How to Do It and Why You Shouldn’t class Array def sum # Also defined in `activesupport`! inject { |sum, x| sum + x } end end ! expect([1, 2, 3].sum).to eq 6 Monkey patching can lead to cryptic errors
  • 6. Monkey Patching Root Objects Go Big or Go Home class Object def should # ... end end module Kernel def describe # ... end end # Global method describe # All objects respond # to method Object.new.should
  • 7. Monkey Patching Root Objects Go Big or Go Home class Object def should # ... end end module Kernel def describe # ... end end # Global method describe # All objects respond # to method Object.new.should
  • 8. Monkey Patching Root Objects Go Big or Go Home class Object def should # ... end end module Kernel def describe # ... end end # Global method describe # All objects respond # to method Object.new.should
  • 9. Monkey Patching Root Objects Go Big or Go Home class Object def should # ... end end module Kernel def describe # ... end end # Global method describe # All objects respond # to method Object.new.should
  • 10. Monkey Patching Root Objects Go Big or Go Home class Object def should # ... end end module Kernel def describe # ... end end # Global method describe # All objects respond # to method Object.new.should
  • 11. RSpec 3.0 Historically, RSpec has extensively used monkey patching to create its readable syntax, adding methods…to every object. ! In the last few 2.x releases, we’ve worked towards reducing the amount of monkey patching done by RSpec. Zero Monkey-Patching Mode Myron Marston, RSpec Core Member @myronmarston
  • 12. RSpec 3.0 Achieving“Zero Monkey-Patching Mode” $ rspec meetup_spec.rb
  • 13. The rspec Executable rspec-core/exe/rspec #!/usr/bin/env ruby ! require 'rspec/core' RSpec::Core::Runner.invoke
  • 14. The rspec Executable rspec-core/exe/rspec #!/usr/bin/env ruby ! require 'rspec/core' RSpec::Core::Runner.invoke
  • 15. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 16. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 17. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 18. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 19. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 20. Loading Spec Files class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 21. Loading Spec Files RSpec::Core::Configuration.load_spec_files def load_spec_files files_to_run.uniq.each { |f| load f } @spec_files_loaded = true end
  • 22. Loading Spec Files RSpec::Core::Configuration.load_spec_files def load_spec_files files_to_run.uniq.each { |f| load f } @spec_files_loaded = true end
  • 23. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 24. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 25. Where Does describe Come From? RSpec::Core::DSL def self.expose_example_group_alias(name) example_group_aliases << name ! (class << RSpec; self; end). __send__(:define_method, name) # ... ! expose_example_group_alias_globally(name) if exposed_globally? # defines on Module end
  • 26. Where Does describe Come From? RSpec::Core::DSL def self.expose_example_group_alias(name) example_group_aliases << name ! (class << RSpec; self; end). __send__(:define_method, name) # ... ! expose_example_group_alias_globally(name) if exposed_globally? # defines on Module end
  • 27. Where Does describe Come From? RSpec::Core::DSL def self.expose_example_group_alias(name) example_group_aliases << name ! (class << RSpec; self; end). __send__(:define_method, name) # ... ! expose_example_group_alias_globally(name) if exposed_globally? # defines on Module end
  • 28. Where Does describe Come From? RSpec::Core::DSL def self.expose_example_group_alias(name) example_group_aliases << name ! (class << RSpec; self; end). __send__(:define_method, name) # ... ! expose_example_group_alias_globally(name) if exposed_globally? # defines on Module end
  • 29. Disabling Module Monkey Patching RSpec.configure do |config| config.expose_dsl_globally = false end ! RSpec.describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do # ... end end Only Top Level describe Blocks Are Affected
  • 30. Disabling Module Monkey Patching RSpec.configure do |config| config.expose_dsl_globally = false end ! RSpec.describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do # ... end end Only Top Level describe Blocks Are Affected
  • 31. Disabling Module Monkey Patching RSpec.configure do |config| config.expose_dsl_globally = false end ! RSpec.describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do # ... end end Only Top Level describe Blocks Are Affected
  • 32. Disabling Module Monkey Patching RSpec.configure do |config| config.expose_dsl_globally = false end ! RSpec.describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do # ... end end Only Top Level describe Blocks Are Affected Opt-in as of RSpec 2.11
  • 33. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 34. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 35. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 36. Building Example Groups describe TokyoRailsMeetup do let(:meetup) { described_class.new } describe '#start' do context 'without a chef' do it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?) .to be_true end end end end Loading a Typical Spec File
  • 37. Building Example Groups Hierarchies of Example Groups and Examples class ExampleGroup def self.example_group(*args, &example_group_block) # ... child = subclass(self, args, &example_group_block) children << child child end ! def self.examples @examples ||= [] end # ... end
  • 38. Building Example Groups Hierarchies of Example Groups and Examples class ExampleGroup def self.example_group(*args, &example_group_block) # ... child = subclass(self, args, &example_group_block) children << child child end ! def self.examples @examples ||= [] end # ... end
  • 39. Building Example Groups Hierarchies of Example Groups and Examples class ExampleGroup def self.example_group(*args, &example_group_block) # ... child = subclass(self, args, &example_group_block) children << child child end ! def self.examples @examples ||= [] end # ... end
  • 40. Building Example Groups Hierarchies of Example Groups and Examples class ExampleGroup def self.example_group(*args, &example_group_block) # ... child = subclass(self, args, &example_group_block) children << child child end ! def self.examples @examples ||= [] end # ... end
  • 41. Building Example Groups Hierarchies of Example Groups and Examples
  • 42. Running the Examples class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 43. Running the Examples class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 44. Running the Examples class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end RSpec::Core::CommandLine.run
  • 45. Running the Examples RSpec::Core::Example.run def run(example_group_instance, reporter) # ... begin run_before_each @example_group_instance. instance_exec(self, &@example_block) rescue Exception => e set_exception(e) ensure run_after_each end end
  • 46. Running the Examples RSpec::Core::Example.run def run(example_group_instance, reporter) # ... begin run_before_each @example_group_instance. instance_exec(self, &@example_block) rescue Exception => e set_exception(e) ensure run_after_each end end
  • 47. Running the Examples RSpec::Core::Example.run def run(example_group_instance, reporter) # ... begin run_before_each @example_group_instance. instance_exec(self, &@example_block) rescue Exception => e set_exception(e) ensure run_after_each end end
  • 48. Running the Examples RSpec::Core::Example.run def run(example_group_instance, reporter) # ... begin run_before_each @example_group_instance. instance_exec(self, &@example_block) rescue Exception => e set_exception(e) ensure run_after_each end end
  • 49. Making Expectations it 'is a grand old time' do meetup.start meetup.should be_hoppin end ! it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?).to be_true end The Deprecated should Syntax
  • 50. Making Expectations it 'is a grand old time' do meetup.start meetup.should be_hoppin end ! it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?).to be_true end The Deprecated should Syntax
  • 51. How should is Monkey Patched class Configuration # ... def syntax=(values) if Array(values).include?(:expect) Expectations::Syntax.enable_expect else Expectations::Syntax.disable_expect end ! if Array(values).include?(:should) Expectations::Syntax.enable_should else Expectations::Syntax.disable_should end end end RSpec::Expectations::Configuration
  • 52. How should is Monkey Patched class Configuration # ... def syntax=(values) if Array(values).include?(:expect) Expectations::Syntax.enable_expect else Expectations::Syntax.disable_expect end ! if Array(values).include?(:should) Expectations::Syntax.enable_should else Expectations::Syntax.disable_should end end end RSpec::Expectations::Configuration
  • 53. How should is Monkey Patched class Configuration # ... def syntax=(values) if Array(values).include?(:expect) Expectations::Syntax.enable_expect else Expectations::Syntax.disable_expect end ! if Array(values).include?(:should) Expectations::Syntax.enable_should else Expectations::Syntax.disable_should end end end RSpec::Expectations::Configuration
  • 54. How should is Monkey Patched class Configuration # ... def syntax=(values) if Array(values).include?(:expect) Expectations::Syntax.enable_expect else Expectations::Syntax.disable_expect end ! if Array(values).include?(:should) Expectations::Syntax.enable_should else Expectations::Syntax.disable_should end end end RSpec::Expectations::Configuration
  • 55. How should is Monkey Patched def enable_should(syntax_host=::Object.ancestors.last) # ... syntax_host.module_exec do def should(matcher=nil, message=nil, &block) # ... end ! def should_not(matcher=nil, message=nil, &block) # ... end end end RSpec::Expectations::Syntax
  • 56. How should is Monkey Patched def enable_should(syntax_host=::Object.ancestors.last) # ... syntax_host.module_exec do def should(matcher=nil, message=nil, &block) # ... end ! def should_not(matcher=nil, message=nil, &block) # ... end end end RSpec::Expectations::Syntax
  • 57. How should is Monkey Patched def enable_should(syntax_host=::Object.ancestors.last) # ... syntax_host.module_exec do def should(matcher=nil, message=nil, &block) # ... end ! def should_not(matcher=nil, message=nil, &block) # ... end end end RSpec::Expectations::Syntax
  • 58. Making Expectations it 'is a grand old time' do meetup.start meetup.should be_hoppin end ! it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?).to be_true end The New expect(…).to Syntax
  • 59. Making Expectations it 'is a grand old time' do meetup.start meetup.should be_hoppin end ! it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?).to be_true end The New expect(…).to Syntax
  • 60. Making Expectations it 'is a grand old time' do meetup.start meetup.should be_hoppin end ! it 'gets everyone drunk' do meetup.start expect(meetup.everyone_wasted?).to be_true end The New expect(…).to Syntax
  • 61. How expect is Implemented def enable_expect(syntax_host=::RSpec::Matchers) # ... syntax_host.module_exec do def expect(*target, &target_block) # ... end end end RSpec::Expectations::Syntax
  • 62. How expect is Implemented def enable_expect(syntax_host=::RSpec::Matchers) # ... syntax_host.module_exec do def expect(*target, &target_block) # ... end end end RSpec::Expectations::Syntax
  • 63. How expect is Implemented def enable_expect(syntax_host=::RSpec::Matchers) # ... syntax_host.module_exec do def expect(*target, &target_block) # ... end end end RSpec::Expectations::Syntax
  • 64. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end
  • 65. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end
  • 66. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end
  • 67. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end
  • 68. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end expect(meetup).to be_hoppin
  • 69. Disabling should Monkey Patching RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] c.syntax = :expect end end ! it 'is a grand old time' do meetup.start meetup.should be_hoppin end expect(meetup).to be_hoppin should Emits Deprecation Warning as of RSpec 3.0
  • 70. Bringing it All Together class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end Load the Specs & Build Example Groups, then Run
  • 71. Bringing it All Together class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end Load the Specs & Build Example Groups, then Run
  • 72. Bringing it All Together class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end Load the Specs & Build Example Groups, then Run
  • 73. Bringing it All Together class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end Load the Specs & Build Example Groups, then Run
  • 74. Bringing it All Together class CommandLine def run(err, out) # ... @configuration.load_spec_files # ... begin @configuration.hooks.run(:before, :suite) @world.ordered_example_groups.map { |g| g.run(reporter) } # ... ensure @configuration.hooks.run(:after, :suite) end end end Load the Specs & Build Example Groups, then Run
  • 75. Want to Learn More about RSpec? • http://modocache.io/rspec-under-the-covers • Expectations in RSpec 3.0 • RSpec Output Formatting • Shared Examples in RSpec ! • Follow me on Twitter and GitHub at @modocache • First person to tweet me gets an Atom invite! #swag ! • Myron Marston’s blog: http://myronmars.to/n/dev-blog