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.