Monday, 8 May 2017

RSpec before hooks

I assume that everybody is familiar with the famous ruby testing framework rspec.

Let's say that we have this spec structure:

require 'rails_helper'

describe 'search_index' do
  context 'entity A' do
    let(!setup_a){ create :a}
...
    before do
      SearchIndex.delete! rescue nil
      SearchIndex.create
      SearchIndex.import
    end
...
  end
...
  context 'entity B' do
    let(!setup_b){ create :b}
...
    before do
      SearchIndex.delete! rescue nil
      SearchIndex.create
      SearchIndex.import
    end
...
  end
end

As we see the before blocks are the same. Some might be tempted to move to a common place.
Let's do this:

require 'rails_helper'

describe 'search_index' do
  before do
    SearchIndex.delete! rescue nil
    SearchIndex.create
    SearchIndex.import
  end

  context 'entity A' do
...
...
  end
...
  context 'entity B' do
...
...
  end
end

At this moment we experience a surprise the the tests are not passing...
If we take a closer look we can easily identify the spot.
The import in the before blocks was run before the setup_b and setup_a was called. So there was nothing to import therefore our expectations run on an empty index.

In this particular case it was much more beneficial to leave the common code where it is.
But wait... Aren't we dealing with a ruby code? Yes of corse. This means that the content of the before can be extracted into a function then called before any context.


require 'rails_helper'

def reinitialise_the_index
  SearchIndex.delete! rescue nil
  SearchIndex.create
  SearchIndex.import
end

describe 'search_index' do
  context 'entity A' do
    let(!setup_a){ create :a}
...
    before do
      reinitialise_the_index
    end
...
  end
...
  context 'entity B' do
    let(!setup_b){ create :b}
...
    before do
      reinitialise_the_index
    end
...
  end
end

Much simpler isn't it?
Happy coding :)