Where developers come to connect, share, build and be inspired.

9

Safe stubbing with bogus

1806 views

In isolated tests in Ruby mocked interfaces may misalign with real ones while codebase grows. It can be avoided by using mocks that verify method definitions and fakes that keep those interfaces in sync.

Let's say we start with a repository class with a following store method:

def store(name)
end

And a controller that uses it:

def create(params)
  repository.store(params[:name])
end

We can test the interaction between them using rr:

it 'stores resources' do
  repository = stub
  mock(repository).store('Penguin') { nil }

  controller = Controller.new(repository)

  controller.create(name: 'Penguin')
end

After a while, we need to store the description as well:

def store(name, description)
end

However the controller test still passes while it is incorrect, because it doesn't know anything about repository interface. It can be easily fixed with Bogus by using fakes.

it 'saves images' do
  repository = fake(:repository)
  mock(repository).store('Penguin') { nil }

  controller = Controller.new(repository)

  controller.create(name: 'Penguin')
end

Now this tests fails with ArgumentError: tried to stub store(name, description) with 1 arguments which points us directly to the source of the problem.

Behind the scenes Bogus creates fakes by copying the public interface of repository, it adds mocking syntax that mimics the rr and verifies methods existence and arity.

You can find bogus on github and more details in documentation. Examples from this post are here.

Comments

  • Blank-mugshot
    krisleech

    Is this the same as a spie?

  • Blank-mugshot
    wrozka

    Do you mean spy? If so, Bogus supports spies as well, actually that is the recommended way of testing with it.

    In spy mock objectes are created as doubles of given class, which breaks to rule mock roles not objects. In bogus fakes are identified by a symbol, which by convention points to the camelized class, but it can be configured to any other class or even a 'lowest common interface'.

    Another feature that differenties Bogus from rspec-fire or spy are contract test. They make sure that objects tested in isolation can be integrated with each other without any integration tests. However, it is still an experimental part.

Add a comment