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


Safe stubbing with bogus


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)

And a controller that uses it:

def create(params)

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')

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

def store(name, description)

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')

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.


  • Kris_avatar

    Is this the same as a spie?

  • 418b0a31e12a61df6a817a17f4f1d827

    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