Three types of mocks original

by Brent Roose – 3 minute read

Mocking, faking; these might sound like intimidating words if you don't know what they are about, but once you do, you'll be able to improve your testing skills significantly.

Part of "the art of testing" is being able to test code in some level of isolation to make sure a test suite is trustworthy and versatile. These topics are so important that we actually made five or six videos on them in our Testing Laravel course.

In this post, I want to share three ways how you can deal with mocking and faking. Let's dive in!

Laravel's Fakes

Laravel has seven fakes — eight if you count time as well:

  • Bus
  • Event
  • HTTP
  • Mail
  • Notification
  • Queue
  • Storage
  • Time

Laravel fakes are useful because they are built-in ways to disable some of the core parts of the framework during testing while still being able to make assertions on them. Here's an example of using the Storage fake to assert whether a file would have been saved in the correct place if the code was run for real, outside of your test suite:

Storage::fake('public');

$post = BlogPost::factory()->create();

Storage::disk('public')
    ->assertExists("blog/{$post->slug}.png");

Mockery

Laravel has built-in support for Mockery, a library that allows you to create mocks — fake implementations of a class — on the fly.

Here we create an example of an RssRepository, so that we won't perform an actual HTTP request, but instead return some dummy data:

$rss = $this->mock(
    RssRepository::class,
    function (MockInterface $mock) {
        $mock
            ->shouldReceive('fetch')
            ->andReturn(collect([
                new RssEntry(/* … */)
            ]));
    }
);

You can imagine how using mocks can significantly impact the performance and reliability of your test suite.

Handcrafted mocks

Mockery can sometimes feel heavy or complex, depending on your use case. My personal preference is to use handcrafted mocks instead: a different implementation of an existing class, one that you register in Laravel's container when running tests. Here's an example:

class RssRepositoryFake extends RssRepository
{
    public function fetch(string $url): Collection
    {
        return collect([
            new RssEntry(/* … */),
        ]);
    }

    public static function setUp(): void
    {
        self::$urls = [];

        app()->instance(
            RssRepository::class,
            new self(),
        );
    }
}

By cleverly using the service container, we can override our real RssRepository by one that doesn't actually perform any HTTP requests. If you're curious to learn more about them, you can check out our Testing Laravel course.

Join 9,500+ smart developers

Get my monthly newsletter with what I learn from running Spatie, building Oh Dear, and maintaining 300+ open source packages. Practical takes on Laravel, PHP, and AI that you can actually use.

"Freek publishes a super resourceful and practical newsletter. A must for anyone in the Laravel space"

Joey Kudish — Shipping with AI as a teammate

No spam. Unsubscribe anytime. You can also follow me on X.

Found something interesting to share? Submit a link to the community section.