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;
- Swapped
output.should
fordate_version.should
which would force rspec not to change my DateTime into a String. - Used
eql
instead of==
which does not do type conversion. - 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.