Rspec's be_an_instance_of is pretty useful

A handy little method I found when testing my application with RSpec

Today I was testing a small helper method I had written that would convert a String to a date or if it was already a DateTime object it would just return it. A pretty simple function but one that needs testing all the same.

Initially my test looked something like this;

require 'spec_helper'
require 'date'
require 'time'

describe MyHelper do
  describe 'convert_to_datetime functionality' do
    let(:input) { '2012-03-04' }
    let(:date_version) { DateTime.parse(input) }

    it 'should successfully convert a well formatted date string' do
      output = convert_to_datetime input
      output.should == date_version
    end

    it 'should return the original date if a DateTime object was passed in' do
      output = convert_to_datetime date_version
      output.should == date_version
    end
  end
end

On the face of it this would seem to work, and indeed all the tests pass, but what if I changed output.should == date_version to output.should == input? Instant fail? Nope!

The reason why this also passes is because I am including ActiveSupport earlier on in the code and with that included so long as the String when converted to a DateTime is the same DateTime then .should == will pass.

This was unexpected, but fortunately I very quickly found be_an_instance_of, what this allows us to do is check that a variable is an instance of a particular class, in our example a DateTime class.

Now my code reads;

require 'spec_helper'
require 'date'
require 'time'

describe MyHelper do
  describe 'convert_to_datetime functionality' do
    let(:input) { '2012-03-04' }
    let(:date_version) { DateTime.parse(input) }

    it 'should successfully convert a well formatted date string' do
      output = convert_to_datetime input
      output.should be_an_instance_of(DateTime)
      output.should == date_version
    end

    it 'should return the original date if a DateTime object was passed in' do
      output = convert_to_datetime date_version
      output.should be_an_instance_of(DateTime)
      output.should == date_version
    end
  end
end

Which is a more solid check.

Update

Some nice folk on Reddit pointed out that I could have done one of the following;

  1. Swapped output.should for date_version.should which would force rspec not to change my DateTime into a String.
  2. Used eql instead of == which does not do type conversion.
  3. Using be_instance_of can make your code a little harder to read and might end up coupling your test to a particular data type and if that changes you could end up with stuff to fix.

Recent posts View all

Ruby

Forcing a Rails database column to be not null

How you can force a table column to always have something in it with Rails

Writing Marketing

We've deleted an article's worth of unhelpful words

We've improved several pages across our site by removing words that add no value, and often detract from the article.