Using before(:context) / before(:all) in RSpec will cause you lots of trouble unless you know what you are doing

Updated . Posted . Visible to the public.

TL;DR Avoid before(:context) (formerly before(:all)), use before(:example) (formerly before(:each)) instead.

If you do use before(:context), you need to know what you are doing and take care of any cleanup yourself.

Why?

Understand this:

  • before(:context) is run when the context/describe block begins,
  • before(:context) is run outside of transactions, so data created here will bleed into other specs
  • before(:example) is run before each spec inside it,

Generally, you'll want a clean setup for each spec so that they are independent of other specs in the same context.

Example

Consider this spec:

describe User, 'something' do
  before :context do
    @user = User.make
  end

  it 'should so something' do
    # ...
  end

  it 'should so something else' do
    # ...
  end
end

If you do that, @user will not be re-created for each test. Obviously, this has significant downsides, mostly that changes of one test on that record will bleed into the next one. \
Also, when using DatabaseCleaner with the :deletion strategy, the record will be gone after the first spec.

Doing it right

before(:example) is the right choice in most cases. So, for the above example we say the following and all is well.

describe User, 'something' do
  before :example do
    @user = User.make
  end

  # ...
end

Furthermore, you will probably run into trouble with your RSpec configuration block that does things in config.before(:example), as this will also be run after your individual spec's before(:context) block did things and might revert changes.

Always use before(:example) unless you are totally sure of the impact your before(:context) block has.

Profile picture of Arne Hartherz
Arne Hartherz
Last edit
Daniel Straßner
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2012-09-20 08:54)