Skip to content

WARNING You're browsing the documentation for an old version of Laravel. Consider upgrading your project to Laravel 12.x.

Mocking

Introduction

When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller's HTTP response without worrying about the execution of the event listeners, since the event listeners can be tested in their own test case.

Laravel provides helpers for mocking events, jobs, and facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls. You can also use Mockery or PHPUnit to create your own mocks or spies.

Bus Fake

As an alternative to mocking, you may use the Bus facade's fake method to prevent jobs from being dispatched. When using fakes, assertions are made after the code under test is executed:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use App\Jobs\ShipOrder;
7use Illuminate\Support\Facades\Bus;
8use Illuminate\Foundation\Testing\RefreshDatabase;
9use Illuminate\Foundation\Testing\WithoutMiddleware;
10 
11class ExampleTest extends TestCase
12{
13 public function testOrderShipping()
14 {
15 Bus::fake();
16 
17 // Perform order shipping...
18 
19 Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) {
20 return $job->order->id === $order->id;
21 });
22 
23 // Assert a job was not dispatched...
24 Bus::assertNotDispatched(AnotherJob::class);
25 }
26}

Event Fake

As an alternative to mocking, you may use the Event facade's fake method to prevent all event listeners from executing. You may then assert that events were dispatched and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use App\Events\OrderShipped;
7use App\Events\OrderFailedToShip;
8use Illuminate\Support\Facades\Event;
9use Illuminate\Foundation\Testing\RefreshDatabase;
10use Illuminate\Foundation\Testing\WithoutMiddleware;
11 
12class ExampleTest extends TestCase
13{
14 /**
15 * Test order shipping.
16 */
17 public function testOrderShipping()
18 {
19 Event::fake();
20 
21 // Perform order shipping...
22 
23 Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {
24 return $e->order->id === $order->id;
25 });
26 
27 // Assert an event was dispatched twice...
28 Event::assertDispatched(OrderShipped::class, 2);
29 
30 // Assert an event was not dispatched...
31 Event::assertNotDispatched(OrderFailedToShip::class);
32 }
33}

After calling Event::fake(), no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model's creating event, you should call Event::fake() after using your factories.

Faking A Subset Of Events

If you only want to fake event listeners for a specific set of events, you may pass them to the fake or fakeFor method:

1/**
2 * Test order process.
3 */
4public function testOrderProcess()
5{
6 Event::fake([
7 OrderCreated::class,
8 ]);
9 
10 $order = factory(Order::class)->create();
11 
12 Event::assertDispatched(OrderCreated::class);
13 
14 // Other events are dispatched as normal...
15 $order->update([...]);
16}

Scoped Event Fakes

If you only want to fake event listeners for a portion of your test, you may use the fakeFor method:

1<?php
2 
3namespace Tests\Feature;
4 
5use App\Order;
6use Tests\TestCase;
7use App\Events\OrderCreated;
8use Illuminate\Support\Facades\Event;
9use Illuminate\Foundation\Testing\RefreshDatabase;
10use Illuminate\Foundation\Testing\WithoutMiddleware;
11 
12class ExampleTest extends TestCase
13{
14 /**
15 * Test order process.
16 */
17 public function testOrderProcess()
18 {
19 $order = Event::fakeFor(function () {
20 $order = factory(Order::class)->create();
21 
22 Event::assertDispatched(OrderCreated::class);
23 
24 return $order;
25 });
26 
27 // Events are dispatched as normal and observers will run ...
28 $order->update([...]);
29 }
30}

Mail Fake

You may use the Mail facade's fake method to prevent mail from being sent. You may then assert that mailables were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use App\Mail\OrderShipped;
7use Illuminate\Support\Facades\Mail;
8use Illuminate\Foundation\Testing\RefreshDatabase;
9use Illuminate\Foundation\Testing\WithoutMiddleware;
10 
11class ExampleTest extends TestCase
12{
13 public function testOrderShipping()
14 {
15 Mail::fake();
16 
17 // Assert that no mailables were sent...
18 Mail::assertNothingSent();
19 
20 // Perform order shipping...
21 
22 Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {
23 return $mail->order->id === $order->id;
24 });
25 
26 // Assert a message was sent to the given users...
27 Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
28 return $mail->hasTo($user->email) &&
29 $mail->hasCc('...') &&
30 $mail->hasBcc('...');
31 });
32 
33 // Assert a mailable was sent twice...
34 Mail::assertSent(OrderShipped::class, 2);
35 
36 // Assert a mailable was not sent...
37 Mail::assertNotSent(AnotherMailable::class);
38 }
39}

If you are queueing mailables for delivery in the background, you should use the assertQueued method instead of assertSent:

1Mail::assertQueued(...);
2Mail::assertNotQueued(...);

Notification Fake

You may use the Notification facade's fake method to prevent notifications from being sent. You may then assert that notifications were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use App\Notifications\OrderShipped;
7use Illuminate\Support\Facades\Notification;
8use Illuminate\Notifications\AnonymousNotifiable;
9use Illuminate\Foundation\Testing\RefreshDatabase;
10use Illuminate\Foundation\Testing\WithoutMiddleware;
11 
12class ExampleTest extends TestCase
13{
14 public function testOrderShipping()
15 {
16 Notification::fake();
17 
18 // Assert that no notifications were sent...
19 Notification::assertNothingSent();
20 
21 // Perform order shipping...
22 
23 Notification::assertSentTo(
24 $user,
25 OrderShipped::class,
26 function ($notification, $channels) use ($order) {
27 return $notification->order->id === $order->id;
28 }
29 );
30 
31 // Assert a notification was sent to the given users...
32 Notification::assertSentTo(
33 [$user], OrderShipped::class
34 );
35 
36 // Assert a notification was not sent...
37 Notification::assertNotSentTo(
38 [$user], AnotherNotification::class
39 );
40 
41 // Assert a notification was sent via Notification::route() method...
42 Notification::assertSentTo(
43 new AnonymousNotifiable, OrderShipped::class
44 );
45 }
46}

Queue Fake

As an alternative to mocking, you may use the Queue facade's fake method to prevent jobs from being queued. You may then assert that jobs were pushed to the queue and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use App\Jobs\ShipOrder;
7use Illuminate\Support\Facades\Queue;
8use Illuminate\Foundation\Testing\RefreshDatabase;
9use Illuminate\Foundation\Testing\WithoutMiddleware;
10 
11class ExampleTest extends TestCase
12{
13 public function testOrderShipping()
14 {
15 Queue::fake();
16 
17 // Assert that no jobs were pushed...
18 Queue::assertNothingPushed();
19 
20 // Perform order shipping...
21 
22 Queue::assertPushed(ShipOrder::class, function ($job) use ($order) {
23 return $job->order->id === $order->id;
24 });
25 
26 // Assert a job was pushed to a given queue...
27 Queue::assertPushedOn('queue-name', ShipOrder::class);
28 
29 // Assert a job was pushed twice...
30 Queue::assertPushed(ShipOrder::class, 2);
31 
32 // Assert a job was not pushed...
33 Queue::assertNotPushed(AnotherJob::class);
34 
35 // Assert a job was pushed with a specific chain...
36 Queue::assertPushedWithChain(ShipOrder::class, [
37 AnotherJob::class,
38 FinalJob::class
39 ]);
40 }
41}

Storage Fake

The Storage facade's fake method allows you to easily generate a fake disk that, combined with the file generation utilities of the UploadedFile class, greatly simplifies the testing of file uploads. For example:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use Illuminate\Http\UploadedFile;
7use Illuminate\Support\Facades\Storage;
8use Illuminate\Foundation\Testing\RefreshDatabase;
9use Illuminate\Foundation\Testing\WithoutMiddleware;
10 
11class ExampleTest extends TestCase
12{
13 public function testAvatarUpload()
14 {
15 Storage::fake('avatars');
16 
17 $response = $this->json('POST', '/avatar', [
18 'avatar' => UploadedFile::fake()->image('avatar.jpg')
19 ]);
20 
21 // Assert the file was stored...
22 Storage::disk('avatars')->assertExists('avatar.jpg');
23 
24 // Assert a file does not exist...
25 Storage::disk('avatars')->assertMissing('missing.jpg');
26 }
27}

By default, the fake method will delete all files in its temporary directory. If you would like to keep these files, you may use the "persistentFake" method instead.

Facades

Unlike traditional static method calls, facades may be mocked. This provides a great advantage over traditional static methods and grants you the same testability you would have if you were using dependency injection. When testing, you may often want to mock a call to a Laravel facade in one of your controllers. For example, consider the following controller action:

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Support\Facades\Cache;
6 
7class UserController extends Controller
8{
9 /**
10 * Show a list of all users of the application.
11 *
12 * @return Response
13 */
14 public function index()
15 {
16 $value = Cache::get('key');
17 
18 //
19 }
20}

We can mock the call to the Cache facade by using the shouldReceive method, which will return an instance of a Mockery mock. Since facades are actually resolved and managed by the Laravel service container, they have much more testability than a typical static class. For example, let's mock our call to the Cache facade's get method:

1<?php
2 
3namespace Tests\Feature;
4 
5use Tests\TestCase;
6use Illuminate\Support\Facades\Cache;
7use Illuminate\Foundation\Testing\RefreshDatabase;
8use Illuminate\Foundation\Testing\WithoutMiddleware;
9 
10class UserControllerTest extends TestCase
11{
12 public function testGetIndex()
13 {
14 Cache::shouldReceive('get')
15 ->once()
16 ->with('key')
17 ->andReturn('value');
18 
19 $response = $this->get('/users');
20 
21 // ...
22 }
23}

You should not mock the Request facade. Instead, pass the input you desire into the HTTP helper methods such as get and post when running your test. Likewise, instead of mocking the Config facade, call the Config::set method in your tests.

Laravel is the most productive way to
build, deploy, and monitor software.