SyntaxStudy
Sign Up
Laravel Testing with actingAs, Mocking, and Fakes
Laravel Beginner 1 min read

Testing with actingAs, Mocking, and Fakes

The actingAs() method authenticates a user for a single test request, accepting a User model instance. It sets the authenticated user in the session (for web tests) or as a token user (for API tests with actingAs($user, 'sanctum')). This eliminates the need to make a login request in every test that requires authentication, keeping tests fast and focused. Laravel provides built-in fakes for external services to prevent real side effects during tests. Mail::fake() stops emails from being sent. Queue::fake() prevents jobs from being dispatched to a real queue. Event::fake() blocks event listeners from firing. Notification::fake() intercepts notifications. Storage::fake() uses a temporary disk. After faking, you can assert these interactions happened with assert methods. Mocking with Mockery or Laravel's own $this->mock() method replaces service container bindings with mock objects. This is used when a service has side effects (calling an external API) or when you want to control its return values in tests. The $this->spy() method creates a spy that calls the real implementation but also records all calls for later assertion. Partial mocks use mockPartial() to override only specific methods.
Example
<?php
// tests/Feature/OrderTest.php

namespace Tests\Feature;

use App\Jobs\ProcessOrder;
use App\Mail\OrderConfirmation;
use App\Models\Order;
use App\Models\User;
use App\Notifications\OrderShipped;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class OrderTest extends TestCase
{
    use RefreshDatabase;

    public function test_placing_an_order_dispatches_job_and_sends_email(): void
    {
        Queue::fake();
        Mail::fake();
        Notification::fake();

        $user = User::factory()->create();

        $response = $this->actingAs($user, 'sanctum')
            ->postJson('/api/v1/orders', ['product_id' => 1, 'quantity' => 2]);

        $response->assertCreated();

        Queue::assertPushed(ProcessOrder::class, function ($job) use ($user) {
            return $job->order->user_id === $user->id;
        });

        Mail::assertQueued(OrderConfirmation::class, fn($mail) =>
            $mail->hasTo($user->email)
        );

        Notification::assertSentTo($user, OrderShipped::class);
    }
}