Mocking, stubbing and spying are about the methods, NOT about the objects themselves.
It is confusing to call a test double a “mock” or a “stub”. A single instance could have a method mocked, another method stubbed, and yet another method be a spy. That object is always just a “test double”. The methods are mocked, stubbed or spied.
What are they?
These examples are written in ruby with RSpec, whose syntax should be understandable even if you haven’t seen it before.
In each example, I also annotate the three parts of a test:
- Arrange all necessary preconditions and inputs.
- Act on the object or method under test.
- Assert that the expected results have occurred.
Here is an example of stubbing:
Let’s just think of
dog as a “test double”. We can then say that we have
walk method or that we have stubbed the response to the
This test follows the
Arrange-Act-Assert ordering. It
also doesn’t care whether or not we sent the
walk message to
dog. It only
walker.walk(dog) returned true.
Here is an example of mocking:
In this example, many would refer to
dog as a mock. Instead, let’s think of
dog as a “test double”, or just a “double”. Then, we can say that we have
An important thing to note here is that this test does not follow the typical
Arrange-Act-Assert mode for
testing. When mocking, you must set your expectation before you act. In other
words, the Assertion comes before the Action. This may seem innocuous, but it
can hide subtle problems. If one were to pull the expectation up into a
:each, then every spec would now have an extra assertion. Furthermore, it is
surprising to see a test that ends with an action. Future developers may think
you left off the assertion.
Spying on Methods
Finally, an example of spying:
When we set up a spy in RSpec, we first stub the method. RSpec does not
differentiate between spies and stubs in the Arrange phase. This is very
helpful because it means that we can share setup across multiple tests. Some
tests may not care to assert that
dog received the
walk message, but others
may. The stub may still be necessary for all tests, but, unlike with mocking,
we have the ability to only assert when we want to.
Spying allows you to assert that a message was received without breaking the Arrange-Act-Assert ordering.
There are shortcuts to setting up spies in RSpec. You can do:
By doing this, you no longer need the
allow, which is quite convenient. The
double will record every message sent to it. Because of this, we can break from
the main argument of this post and refer to double as a spy.
When do I use them?
Methods should fall into one of the two categories: query or command. Martin Fowler gives these definitions:
- Queries: Return a result and do not change the observable state of the system (are free of side effects).
- Commands: Change the state of a system but do not return a value.
Stub if your system under test is calling another object’s query method. Your system under test will typically do something with that result and you can test what it does with the result. You do not actually care if that query method is called as long as the system under test ultimately does what it should.
Spy if you want to ensure that a message was a received by your test double. This is necessary when you are calling a command method.
Do not bother mocking. Mocking can save you a line of code (unless you use
as_null_object), but it breaks the Arrange-Act-Assert test
structure. Ultimately, they do the same thing, but spying is more flexible and
easier to reason about.
For further discussion on Queries vs Command and when to test in which way, I would suggest that you watch Sandi Metz’s talk: Magic Tricks of Testing. It is quite good.