Open AdamEsterle opened 7 years ago
Here's a good presentation by Dave Marshall that covers the differences:
https://www.youtube.com/watch?v=6_r3AzRg1HM
I also wrote about it once here:
https://adamwathan.me/2014/09/22/when-to-mock/
Mocks, fakes, spies, stubs, and dummies are all specific types of test doubles, which is the more general term.
Stubs and dummies are different flavors of the same test double; they both just take the place of some dependency in a test, but have no ability to trigger a test failure.
A dummy usually just swallows method calls, returns null to things, etc. It's usually meant to be used in place of a parameter that's not actually invoked in a certain test.
A stub is a test double that's programmed to return canned responses to different method calls.
In this test, those (object) ['price' => 1200]
objects are stubs of real Ticket objects, even though we aren't using a test double library.
Mocks and spies are test doubles that can trigger a test failure if they aren't interacted with correctly.
With a mock, you specify mock expectations which describe how the double should be used in advance, and if it's not used that way, the test will fail.
For example:
$ticket = Mockery::mock(Ticket::class);
$ticket->shouldReceive('release')->once();
If the release
method isn't called, the test will fail.
A spy is very similar to a mock, except they allow you to specify the expectation at the end of the test, instead of in the beginning:
$ticket = Mockery::spy(Ticket::class);
// ...rest of the test goes here...
$ticket->shouldHaveReceived('release');
I talk about some of the benefits of using spies over mocks in this blog post:
Fakes are the most sophisticated kind of test double, and can't be created using a library.
A fake is a real implementation of some collaborator, but implemented in a simpler or more naive way.
Laravel has a bunch of fakes built in that you might not have noticed. For example, there is an array
driver for the Cache, which just caches things in memory for a single request. There's also the sync
driver for the Queue, which of course isn't a real queue, it's just a simple implementation that you can use locally.
SQLite is basically a fake as well 😊
The nice thing about fakes is you can add additional methods to them for making assertions in your tests. We do that a lot with our FakePaymentGateway in the course.
Another major benefit is that they just work from the perspective of the rest of your system. This makes them very useful for application-level tests. I can tell the application to use the FakePaymentGateway instead of the StripePaymentGateway, even if payments aren't the primary focus of the test. This allows the rest of the code to just work because it doesn't know that the payment gateway is fake, and I also don't have to load my test up with details about all the methods the fake is allowed to receive and how it should respond, like I would with a mock or a stub.
You can write a fake once and use it everywhere in your application, asserting things about it through an interface that the fake exposes to you. This is a lot nicer than creating a new mock by hand every time you need to swap that class with a test double.
Hope that helps!
Great question, fantastic answer. Cheers!
@adamwathan Thank you a bunch for the answer! The theory is starting to make more and more sense. I hope that when I start writing my own tests (very soon here), that I will get that long sought after "click" and things will finally make sense. I really love the series so far; you truly have much expertise.
Thanks for the detailed answer! :+1:
Any blogs/articles/videos that I can check out to help better understand the following? (what each is, differences, when to use one over the other, etc.)