Frank
Frank

Reputation: 189

Practical example of mock and stubs in rails

There is enough questions which are related to this topic, but none provide practial example citing the difference.

According to Fowler's article mocks are not stubs, stubs are fake methods independent from outside calls, while mocks are fake objects with pre-programmed reactions to calls.

Stub's can't make your test fail, but Mocks can.

Mocking is more specific and object-related: if certain parameters are passed, then the object returns certain results. The behavior of an object is imitated or "mocked".

Stubbing is more general and method-related: a stubbed method usually returns always the same result for all parameters. The behavior of a method is frozen, canned or "stubbed".

Let's take a simple test case. We have to find a Book provided with id and related to user.

  it "can find an Book that this user belongs to" do 
    project = Book.find( id: '22', email: [email protected] )      
    expect(project) to eq(some_data);  
  end

In the above case... What is stub and What is mock? If my example is not valid, can anyone show me example of Mock and stub.

Upvotes: 2

Views: 1604

Answers (1)

apneadiving
apneadiving

Reputation: 115521

Lets get two examples:

let(:email) { 'email' }

# object created from scratch
let(:mocked_book) { instance_double Book, email: email } 
it 'check mock' do
  expect(mocked_book.email).to eq email
end

# 
let(:book) { Book.new }
it 'check stub' do
  allow(book).to receive(:email) { email }
  expect(book.email).to eq email
end

Your example is not that relevant: you wouldnt test active record, but you could need to stub it to return a mock

Say you need to test a book receives a method, something like:

def destroy
  @book = Book.find(params[:id])
  if @book.destroyable?
    @book.destroy
  else
    flash[:error] = "errr"
  end
  redirect_to books_path
end

You could test with this code:

it 'is not destroyed if not destroyable' do
  mocked_book = double 'book', destroyable?: false
  allow(Book).to receive(:find).and_return mocked_book
  expect(mocked_book).to_not receive :destroy
  # here goes the code to trigger the controller action
end

it 'is destroyed if destroyable' do
  mocked_book = double 'book', destroyable?: true
  allow(Book).to receive(:find).and_return mocked_book
  expect(mocked_book).to receive :destroy
  # here goes the code to trigger the controller action
end

You can see pros and cons here:

  • cons: mocks must know exactly what are the expected methods

  • pros: with mocks you dont need to really create an object and set it up to make it fit some conditions

Upvotes: 1

Related Questions