logo
podcast Podcast
get help Get Unstuck

When would I use a mock versus a spy?

Both have cool names

Joel Clermont
Joel Clermont
2025-03-21

I was recently re-reading the Mockery docs (I sure know how to have fun!) and was reminded of the different use cases for mocks and spies.

Tests are often grouped into three blocks of logic:

  • "Arrange" - setting up the test scenario (creating records, building a request payload)
  • "Act" - executing the code under test (calling a method, making an HTTP request)
  • "Assert" - verify what happened (checking the response, checking the database)

That logical grouping makes a lot of sense, and it's easy to follow.

But if you need to mock a service, it starts to jumble your blocks of logic. Since mocks require expectations to be set up before the code under test is executed, you now have a little bit of assertion logic mixed in to your setup logic.

Spies provide a solution to this. You can set up a spy with a single line of code, run the code under test, and then with your other assertions say what you expect to have happened to the spy. This preserves the logical grouping of the test sections, but it comes with some trade-offs:

  • By default, in Mockery, spies are more permissive. A mock will fail if something is called in a way you didn't expect. A spy will happily accept any call. This can lead to passing tests with bugs still present.
  • Because spy assertions happen after the code under test is executed, you can't specify return values or exceptions to be thrown. In these cases, you need to use a mock instead.
  • Spies can be harder to debug. The assertion happens further away from the call site of the mocked service, so if the test fails, you might get a less helpful stack trace.

Because of these limitations, I pretty much always use mocks. The mixing of setup and assertion logic is a slight downside, but I still think the benefits outweigh that one small negative.

Here to help,

Joel

P.S. We all get stuck sometimes! Need a quick pairing session with a Laravel expert to get unstuck?

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice you can use.