Jonathan Bennett

When to expect and when to allow

Knowing when to except and when to allow in an RSpec test is important. When you don’t care about the method being called, use allow. When you do care, use expect.

For instance, I was working on some code that:

  1. Did some stuff
  2. Logged a message
  3. Did more stuff
  4. Logged a message we cared about

The code essentially looked like:

expect(Logger).to receive(:log)
foo = Foo.new
expect(Logger).to receive(:log).with("Foo complete")
foo.do_stuff

This worked great, except it was flaky. Sometimes do_stuff would log multiple times before the one our test cared about. This meant the 2nd expect did not get the right value and the test would sometimes fail. This solution to this was simple, use allow:

allow(Logger).to receive(:log)
foo = Foo.new
expect(Logger).to receive(:log).with("Foo complete")
foo.do_stuff

This change means Logger.log can be called any number of times, but it must be called once with “Foo complete”. No more flaking test.