Click image to enlarge
Blog
Saturday, August 6, 2011
Saturday, July 30, 2011
Gotcha with testing expected params with Bourne/Mocha in Rails Controller
This is something that always trips me up using Bourne (a fork of Mocha, a Ruby mocking and stubbing library) to test expected params in a Rails Controller. Take this spec:
context "with filter" do
before do
get :index, :search => {:brand_id => '1'}
end
it 'should find latest search results' do
SearchResult.should have_received(:latest).with('brand_id' => '1')
end
end
This test fails, but what if I tried this:
context "with filter" do
before do
get :index, :search => {:brand_id => '1'}
end
it 'should find latest search results' do
SearchResult.should have_received(:latest).with(:brand_id => '1')
end
end
This will fail. Note I am now checking the parameters passed using symbols for the keys. I receive the following error:
Failure/Error: SearchResult.should have_received(:latest).with(has_entry(:brand_id => '1'))
expected exactly once, not yet invoked: SearchResult(id: integer, search_id: integer, body: text, source: text, url: string, created_at: datetime, updated_at: datetime).latest(has_entry(:brand_id => '1'))
This is because the params that are passed to the controller have keys as strings rather than symbols:
{'brand_id' => '1'}
So what's the solution? I could actually use HashWithIndifferentAccess which gives access to a Hash using strings or symbols for keys. This is in fact the class that is used for the params hash in the controller:
it 'should find latest search results' do
SearchResult.should have_received(:latest).with(HashWithIndifferentAccess.new(:brand_id => '1'))
end
Or, as a standard practice, when dealing with parameters passed to a controller within a spec, always use strings:
context "with filter" do
before do
get :index, 'search' => {'brand_id' => '1'}
end
it 'should find latest search results' do
SearchResult.should have_received(:latest).with('brand_id' => '1')
end
end
I think this is a lot simpler, cleaner. Interestingly, I didn't pass the brand_id as a Fixnum:
before do
get :index, 'search' => {'brand_id' => 1}
end
I would have got the same error:
Failure/Error: SearchResult.should have_received(:latest).with('brand_id' => 1)
expected exactly once, not yet invoked: SearchResult(id: integer, search_id: integer, body: text, source: text, url: string, created_at: datetime, updated_at: datetime).latest('brand_id' => 1)
As the brand_id is present in the hash as a String, not a Fixnum.
Upgrade RVM and Ruby 1.9.2p290
I've been a little lazy and haven't updated my RVM installation (version 1.1.3, now 1.6.31) for a while and have been stuck on Ruby 1.9.2p0. This morning I upgraded, here's what I did:
$ rvm get head $ rvm reload $ rvm install 1.9.2-p290 $ rvm upgrade 1.9.2-p0 1.9.2-p290
Hmm… Got some errors, here's the output:
Are you sure you wish to upgrade from ruby-1.9.2-p0 to ruby-1.9.2-p290? (Y/n): y Migrating gems from ruby-1.9.2-p0 to ruby-1.9.2-p290 Are you sure you wish to MOVE gems from ruby-1.9.2-p0 to ruby-1.9.2-p290? This will overwrite existing gems in ruby-1.9.2-p290 and remove them from ruby-1.9.2-p0 (Y/n): y Moving gemsets... Moving ruby-1.9.2-p0 to ruby-1.9.2-p290 Making gemset ruby-1.9.2-p290 pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@brandizzle to ruby-1.9.2-p290@brandizzle Making gemset ruby-1.9.2-p290@brandizzle pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@default to ruby-1.9.2-p290@default Making gemset ruby-1.9.2-p290@default pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@global to ruby-1.9.2-p290@global Making gemset ruby-1.9.2-p290@global pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@peters-guide to ruby-1.9.2-p290@peters-guide Making gemset ruby-1.9.2-p290@peters-guide pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@refinery to ruby-1.9.2-p290@refinery Making gemset ruby-1.9.2-p290@refinery pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@shoedazzle to ruby-1.9.2-p290@shoedazzle Making gemset ruby-1.9.2-p290@shoedazzle pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@spree to ruby-1.9.2-p290@spree Making gemset ruby-1.9.2-p290@spree pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@sproutcore to ruby-1.9.2-p290@sproutcore Making gemset ruby-1.9.2-p290@sproutcore pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Moving ruby-1.9.2-p0@storeworks to ruby-1.9.2-p290@storeworks Making gemset ruby-1.9.2-p290@storeworks pristine. ERROR: Error running 'rvm gemset pristine' under , please read /Volumes/Data/Users/nicholas/.rvm/log//gemset.pristine.log Do you wish to move over aliases? (Y/n): y Updating alias default to point to ruby-1.9.2-p290@default Do you wish to move over wrappers? (Y/n): Y Do you also wish to completely remove ruby-1.9.2-p0 (inc. archive)? (Y/n): Y ERROR: Error running 'rvm remove ruby-1.9.2-p0 --archive --gems' under , please read /Volumes/Data/Users/nicholas/.rvm/log//rvm.remove.log Successfully migrated ruby-1.9.2-p0 to ruby-1.9.2-p290 Upgrade complete!
Note that I opted to move over aliases, wrappers and completely remove my old ruby-1.9.2-p0.
Looking at the gemset.pristine.log I had the following errors for each gemset:
[2011-07-30 09:08:04] rvm gemset pristine # under ruby-1.9.2-p290@brandizzle /Volumes/Data/Users/nicholas/.rvm/scripts/functions/environment: line 235: rvm: command not found
So for each gemset I executed the following:
rvm gemset pristine
This seemed to work fine. Next, I checked out the errors in rvm.remove.log:
[2011-07-30 09:08:32] rvm remove ruby-1.9.2-p0 --archive --gems # under ruby-1.9.2-p0 /Volumes/Data/Users/nicholas/.rvm/scripts/functions/environment: line 235: rvm: command not found
Looks like the remove of my old 1.9.2 install failed, so I ran it manually:
rvm remove ruby-1.9.2-p0 --archive --gems
Boom! Everything is updated and working.
Thursday, July 28, 2011
Basic Heroku addons I always use for production websites
heroku addons
cron:daily
custom_domains:basic
logging:expanded
memcache:5mb
newrelic:standard
pgbackups:auto-month
sendgrid:basic
shared-database:5mb