Mocking or Spying

Healthify has recently been making an effort to transfer our acceptance tests from Cucumber to RSpec (why we are, is another blog post entirely). One feature we were transferring in particular helped highlight what I believe to be a flaw in how I've been using RSpec throughout our unit tests.

One of the pluses to Cucumber is that the "Background, When, Then" syntax clearly mimics the logical testing pattern of "Arrange, Act, Assert." Without that structure though, I've been mocking methods quite liberally in our unit tests:

expect(something).to receive(:method_name)  

I've always known what this did but never truly considered the implications till I had to do a slightly more complex background for a feature spec. For those who don't know, this effectively does the following:

allow(something).to receive(:method_name)  
expect(something).to have_received(:method_name)  

This usually is what I am looking for. Unfortunately, in the case where I needed to have different stubbed responses at different times in the test, this was a little heavy handed and the magic behind a mock expectation made it unclear to me what was happening.

As soon as I replaced the mock with a spy and stub, then everything became much easier to manage:

# Arrange: Set up your stubs first
allow(something).to receive(:method_name)

# Act: Do whatever you think will trigger your stubs

# Assert: Set up your spys to check whether your stubs were used
expect(something).to have_received(:method_name)