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 :)


Friday 5 June 2015

Available at Toptal

Hi,

I would like to announce that I joined total.

I am available for hire at:
http://www.toptal.com/ruby-on-rails#efficient-professional-web-development


Wednesday 6 May 2015

The benefit of the squeel gem over standard active record

The benefit of the squeel gem over the standard active record

Let's try this query:
Field.where(id: 10).unscope(where: :id)
It results in the below SQL:
"SELECT \"fields\".* FROM \"fields\"

Let try to unscope something a bit more difficult:
Field.where('id > 10').unscope(where: :id)
In this case the unscoping didn't work as we intended:
SELECT \"fields\".* FROM \"fields\" WHERE (id > 10)


Let's try now by using squeel gem:
Field.where{id > 10}.unscope(where: :id).to_sql
Now the unstopping works just as we intended:
"SELECT \"fields\".* FROM \"fields\""

Enjoy :)

Friday 16 January 2015

Testing the ActiveRecord models using Rspec

Usually the skeleton of my models spec looks like this:

require 'spec_helper'
                        
describe Car do
                        
  context 'class hierarchy' do
    #Here comes the class hierarchy specification
  end
                        
  context 'fields' do
  end
                        
  context 'assotiations' do
    #Here comes the enumeration of associations
  end
                        
  context 'validations' do
    #Here comes the validation of models
  end
                        
  context 'callbacks' do
    #Specs for callbacks
  end
                        
  context 'methods' do
  end
end

Testing the class hierarchy:
Since the model could include modules which affect the functionality I consider it necessary to assert on them.

describe Car do
  context 'class hierarchy' do
    specify {expect(subject.class).to be < ActiveRecord::Base}
    specify{expect(subject).to be_kind_of(Elasticsearch::Model)}
    specify{expect(subject).to be_kind_of(Elasticsearch::Model::Callbacks)}
  end
end

Testing the fields:
I often encountered errors when the model was expected to have a field and that field was missing. So I always assert on the used fields:

describe Car do
  context 'fields' do
    specify {expect(subject).to respond_to(:name)}
    specify {expect(subject).to respond_to(:filter)}
  end
end

Testing the associations:
I test the presence of the correct associations using the 'shoulda-matchers' gem.

describe Car do
  context 'assotiations' do
    specify { expect(subject).to belong_to(:user) }
    specify { expect(subject).to belong_to(:manufacturer) }
  end
end

Testing the validations:
I usually test the validations of the fields using the 'shoulda-matchers' gem.

describe Car do
  context 'validations' do
    specify { expect(subject).to validate_uniqueness_of(:filter).scoped_to(:manufacturer_id)}
  end
end

Testing the callbacks:
My callback test usually are like this:

describe Car do
  context 'validations' do
    context 'before_destroy' do
      specify 'call destroy like callback'do
        expect(equipment).to receive(:destroy_likes)
        equipment.destroy
      end
    end
  end
end

Testing the methods:
Usually I test the methods by calling it the asserting that all the necessary changes are made. I do this for all the execution paths.