Logo: Relish

  1. Sign up
  2. Sign in

Project: RSpec Core 3.0

`before` and `after` hooks

Use before and after hooks to execute arbitrary code before and/or after
the body of an example is run:

before(:example) # run before each example
before(:context) # run one time only, before all of the examples in a group

after(:example) # run after each example
after(:context) # run one time only, after all of the examples in a group

before and after blocks are called in the following order:

before :suite
before :context
before :example
after  :example
after  :context
after  :suite

before and after hooks can be defined directly in the example groups they
should run in, or in a global RSpec.configure block.

WARNING: Setting instance variables are not supported in before(:suite).

WARNING: Mocks are only supported in before(:example).

Note: the :example and :context scopes are also available as :each and
:all, respectively. Use whichever you prefer.

Scenarios
Define `before(:example)` block
Given
a file named "before_example_spec.rb" with:
require "rspec/expectations"

class Thing
  def widgets
    @widgets ||= []
  end
end

RSpec.describe Thing do
  before(:example) do
    @thing = Thing.new
  end

  describe "initialized in before(:example)" do
    it "has 0 widgets" do
      expect(@thing.widgets.count).to eq(0)
    end

    it "can accept new widgets" do
      @thing.widgets << Object.new
    end

    it "does not share state across examples" do
      expect(@thing.widgets.count).to eq(0)
    end
  end
end
When
I run rspec before_example_spec.rb
Then
the examples should all pass
Define `before(:context)` block in example group
Given
a file named "before_context_spec.rb" with:
require "rspec/expectations"

class Thing
  def widgets
    @widgets ||= []
  end
end

RSpec.describe Thing do
  before(:context) do
    @thing = Thing.new
  end

  describe "initialized in before(:context)" do
    it "has 0 widgets" do
      expect(@thing.widgets.count).to eq(0)
    end

    it "can accept new widgets" do
      @thing.widgets << Object.new
    end

    it "shares state across examples" do
      expect(@thing.widgets.count).to eq(1)
    end
  end
end
When
I run rspec before_context_spec.rb
Then
the examples should all pass
When
I run rspec before_context_spec.rb:15
Then
the examples should all pass
Failure in `before(:context)` block
Given
a file named "before_context_spec.rb" with:
RSpec.describe "an error in before(:context)" do
  before(:context) do
    raise "oops"
  end

  it "fails this example" do
  end

  it "fails this example, too" do
  end

  after(:context) do
    puts "after context ran"
  end

  describe "nested group" do
    it "fails this third example" do
    end

    it "fails this fourth example" do
    end

    describe "yet another level deep" do
      it "fails this last example" do
      end
    end
  end
end
When
I run rspec before_context_spec.rb --format documentation
Then
the output should contain "5 examples, 5 failures"
And
the output should contain:
an error in before(:context)
  fails this example (FAILED - 1)
  fails this example, too (FAILED - 2)
  nested group
    fails this third example (FAILED - 3)
    fails this fourth example (FAILED - 4)
    yet another level deep
      fails this last example (FAILED - 5)
after context ran
When
I run rspec before_context_spec.rb:9 --format documentation
Then
the output should contain "1 example, 1 failure"
And
the output should contain:
an error in before(:context)
  fails this example, too (FAILED - 1)
Failure in `after(:context)` block
Given
a file named "after_context_spec.rb" with:
RSpec.describe "an error in after(:context)" do
  after(:context) do
    raise StandardError.new("Boom!")
  end

  it "passes this example" do
  end

  it "passes this example, too" do
  end
end
When
I run rspec after_context_spec.rb
Then
the examples should all pass
And
the output should contain:
An error occurred in an after(:context) hook.
  StandardError: Boom!
Define `before` and `after` blocks in configuration
Given
a file named "befores_in_configuration_spec.rb" with:
require "rspec/expectations"

RSpec.configure do |config|
  config.before(:example) do
    @before_example = "before example"
  end
  config.before(:context) do
    @before_context = "before context"
  end
end

RSpec.describe "stuff in before blocks" do
  describe "with :context" do
    it "should be available in the example" do
      expect(@before_context).to eq("before context")
    end
  end
  describe "with :example" do
    it "should be available in the example" do
      expect(@before_example).to eq("before example")
    end
  end
end
When
I run rspec befores_in_configuration_spec.rb
Then
the examples should all pass
`before`/`after` blocks are run in order
Given
a file named "ensure_block_order_spec.rb" with:
require "rspec/expectations"

RSpec.describe "before and after callbacks" do
  before(:context) do
    puts "before context"
  end

  before(:example) do
    puts "before example"
  end

  after(:example) do
    puts "after example"
  end

  after(:context) do
    puts "after context"
  end

  it "gets run in order" do

  end
end
When
I run rspec --format progress ensure_block_order_spec.rb
Then
the output should contain:
before context
before example
after example
.after context
`before`/after` blocks defined in configuration are run in order
Given
a file named "configuration_spec.rb" with:
require "rspec/expectations"

RSpec.configure do |config|
  config.before(:suite) do
    puts "before suite"
  end

  config.before(:context) do
    puts "before context"
  end

  config.before(:example) do
    puts "before example"
  end

  config.after(:example) do
    puts "after example"
  end

  config.after(:context) do
    puts "after context"
  end

  config.after(:suite) do
    puts "after suite"
  end
end

RSpec.describe "ignore" do
  example "ignore" do
  end
end
When
I run rspec --format progress configuration_spec.rb
Then
the output should contain:
before suite
before context
before example
after example
.after context
after suite
`before`/`after` context blocks are run once
Given
a file named "before_and_after_context_spec.rb" with:
RSpec.describe "before and after callbacks" do
  before(:context) do
    puts "outer before context"
  end

  example "in outer group" do
  end

  after(:context) do
    puts "outer after context"
  end

  describe "nested group" do
    before(:context) do
      puts "inner before context"
    end

    example "in nested group" do
    end

    after(:context) do
      puts "inner after context"
    end
  end

end
When
I run rspec --format progress before_and_after_context_spec.rb
Then
the examples should all pass
And
the output should contain:
outer before context
.inner before context
.inner after context
outer after context
When
I run rspec --format progress before_and_after_context_spec.rb:14
Then
the examples should all pass
And
the output should contain:
outer before context
inner before context
.inner after context
outer after context
When
I run rspec --format progress before_and_after_context_spec.rb:6
Then
the examples should all pass
And
the output should contain:
outer before context
.outer after context
Nested examples have access to state set in outer `before(:context)`
Given
a file named "before_context_spec.rb" with:
RSpec.describe "something" do
  before :context do
    @value = 123
  end

  describe "nested" do
    it "access state set in before(:context)" do
      expect(@value).to eq(123)
    end

    describe "nested more deeply" do
      it "access state set in before(:context)" do
        expect(@value).to eq(123)
      end
    end
  end

  describe "nested in parallel" do
    it "access state set in before(:context)" do
      expect(@value).to eq(123)
    end
  end
end
When
I run rspec before_context_spec.rb
Then
the examples should all pass
`before`/`after` context blocks have access to state
Given
a file named "before_and_after_context_spec.rb" with:
RSpec.describe "before and after callbacks" do
  before(:context) do
    @outer_state = "set in outer before context"
  end

  example "in outer group" do
    expect(@outer_state).to eq("set in outer before context")
  end

  describe "nested group" do
    before(:context) do
      @inner_state = "set in inner before context"
    end

    example "in nested group" do
      expect(@outer_state).to eq("set in outer before context")
      expect(@inner_state).to eq("set in inner before context")
    end

    after(:context) do
      expect(@inner_state).to eq("set in inner before context")
    end
  end

  after(:context) do
    expect(@outer_state).to eq("set in outer before context")
  end
end
When
I run rspec before_and_after_context_spec.rb
Then
the examples should all pass
Exception in `before(:example)` is captured and reported as failure
Given
a file named "error_in_before_example_spec.rb" with:
RSpec.describe "error in before(:example)" do
  before(:example) do
    raise "this error"
  end

  it "is reported as failure" do
  end
end
When
I run rspec error_in_before_example_spec.rb
Then
the output should contain "1 example, 1 failure"
And
the output should contain "this error"

Last published about 2 years ago by myronmarston.