Blog

Showing posts with label bourne. Show all posts
Showing posts with label bourne. Show all posts

Friday, March 9, 2012

Testing Terminology: Spies, Stubs and Mocks

When referring to the definitions of Spies, Stubs and Mocks I like to return to XUnit Test Patterns:

  • Test Spy: "We use a Test Double to capture the indirect output calls made to another component by the SUT for later verification by the test."
  • Test Stub: "We replace a real object with a test-specific object that feeds the desired indirect inputs into the SUT."
  • Mock Object: "We replace an object the SUT depends on with a test-specific object that verifies it is being used correctly by the SUT."

You may have noticed that a Spy and Mock seem to have similar definitions, and do serve similar purposes, however Mocks specify expectations up-front and don't require assertions in contrast to Spies, that verify after the fact. Here's an example that compares Rspec Mocks with Bourne's Spies:

SUT is an abbreviation for System Under Test.


The above patterns are collectively know as Test Doubles: "We replace a component on which the SUT depends with a test-specific equivalent." Rspec's built-in mocking library includes a double method/alias, see An Example using RSpec double, mock, and stub.

Double-Ruby (RR) is another example of a test double framework implemented in Ruby.

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.

Please note this blog is no longer maintained. Please visit CivilCode Inc - Custom Software Development.