Fake it by stubbing the mock, dummy
Main Thread • 3 min read
I recently lead a workshop at ZendCon titled Start testing your PHP Code. I have given this workshop a few times. What I continually receive questions about are the different types of mocks (testing objects).
There are indeed differences. I often borrow the definitions from Martin Fowlers TestDouble post (who borrows from Gerard Meszaros)
- Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
- Fakes objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an
InMemoryTestDatabase
is a good example). - Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
- Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.
- Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting.
When you're new to testing, all of this is clear as mud. Often compounded by the fact that these terms are used inconsistently across different testing frameworks.
The differences boil down to slight variations in implementation and usage. For example, the difference between a fake and a stub may simply be the fake has an underlying class. Or the difference between a spy and mock is that a spy also records invocations.
In my opinion, these differences are inconsequential. Often, they only matter when the testing framework makes this differentiation. Unfortunately, Mockery (the mock object framework I demo in my workshop) makes this differentiation.
In Mockery stubs, mocks, and spies are all the same thing. Although it attempts to differentiate between spies and mocks, you still can make verifications on mocks. They only real difference is in their default behavior. A Mockery mock requires you to stub every method used during the test. Whereas a spy does not. If you call a method on a spy in Mockery, it will simply return null
.
In Mockery, there is also the ability to create a partial mock which behaves more like a fake, as it will call through to the implemented (original) method if you do not stub it.
Again, clear as mud.
I like the generic term by Gerard Meszaros - test double. RSpec actually follows this by simply using double()
to create an object that stands in for another object in your system.
That's simple enough. When testing, I don't really care about the differences between test objects. I only care that I can easily create and use a test object.
In the end, although there are indeed differences between test objects, I don't want to be hindered by them while testing. It comes down to developer happiness. Don't make me think!
Using Mockery? I created a simple helper function for Mockery called double()
to abstract all these nuances back to the general use of test doubles and make testing easier.
Find this interesting? Let's continue the conversation on Twitter.