© 2026 Laravel

Laravel's Built-in Fakes for Testing

4 phút đọc

Laravel provides built-in “fakes” that allow you to test interactions with external services without side effects. These fakes capture interactions for later assertions, making your tests faster and more reliable.

Example image
Example image

#Understanding Fakes

#Fake Types Overview

  • Fakes: Working implementations without side effects (like sending emails or storing files)
  • Mocks: Manually configured test doubles that return specific responses
  • Stubs: Simple implementations that return predefined responses

#Benefits of Using Fakes

Laravel’s fakes provide realistic behavior while capturing all interactions for verification, striking the perfect balance between isolation and functionality.

#Mail Fake

#Basic Mail Testing

The Mail fake prevents emails from being sent while recording all mail interactions:

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Support\Facades\Mail;
use App\Mail\OrderConfirmation;
use App\Mail\WelcomeEmail;

class EmailTest extends TestCase
{
    public function test_order_confirmation_email_is_sent(): void
    {
        Mail::fake();

        // Perform order creation that sends email
        $response = $this->post('/orders', [
            'product_id' => 1,
            'quantity' => 2,
            'email' => 'customer@example.com'
        ]);

        // Assert the mail was sent
        Mail::assertSent(OrderConfirmation::class, function ($mail) {
            return $mail->hasTo('customer@example.com');
        });
    }
}

#Mail Assertions

Laravel provides several mail assertions:

Mail::assertSent(WelcomeEmail::class, 2); // Assert count
Mail::assertNothingSent(); // Assert no emails sent
Mail::assertSent(WelcomeEmail::class, function ($mail) {
    return $mail->hasTo('user@example.com');
});

#Storage Fake

#File Upload Testing

The Storage fake provides a local filesystem that mimics your storage disk:

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;

class FileUploadTest extends TestCase
{
    public function test_profile_image_upload(): void
    {
        Storage::fake('public');

        $file = UploadedFile::fake()->image('avatar.jpg', 300, 300);

        $response = $this->post('/profile/avatar', [
            'avatar' => $file
        ]);

        $response->assertRedirect('/profile');

        Storage::disk('public')->assertExists('avatars/avatar.jpg');
    }
}

#Storage Assertions

Common storage assertions for testing file operations:

Storage::disk('public')->assertExists('file.txt');    // File exists
Storage::disk('public')->assertMissing('file.txt');   // File missing
Storage::disk('public')->put('test.txt', 'content'); // Create fake file
$files = Storage::disk('public')->files('uploads');  // List files

#Queue Fake

#Job Testing

The Queue fake prevents jobs from being dispatched while recording them:

Queue::fake();

$this->post('/payments', ['amount' => 100, 'card_token' => 'tok_visa']);

Queue::assertPushed(ProcessPayment::class, function ($job) {
    return $job->amount === 100;
});

#Queue Assertions

Common queue assertions for testing job dispatch:

Queue::assertPushed(JobClass::class);              // Job was pushed
Queue::assertNotPushed(JobClass::class);           // Job was not pushed
Queue::assertPushedOn('queue-name', JobClass::class); // Specific queue
Queue::assertPushed(JobClass::class, 3);           // Count assertion

#Other Fakes

#Event Fake

The Event fake prevents events from firing while recording them:

Event::fake();
$this->post('/register', ['name' => 'John', 'email' => 'john@example.com']);
Event::assertDispatched(UserRegistered::class);

#HTTP Fake

Mock external API responses without making real HTTP requests:

Http::fake([
    'api.example.com/*' => Http::response(['data' => 'response'], 200),
]);

$result = $this->get('/api-call');
Http::assertSent(function ($request) {
    return str_contains($request->url(), 'example.com');
});

#Best Practices

#Usage Guidelines

When working with Laravel’s fakes, follow these guidelines:

  • Always fake before the action: Call the fake method before performing the operation
  • Use specific assertions: Laravel provides detailed assertion methods for each fake type
  • Reset fakes between tests: Each test should start with a clean fake state
  • Test realistic scenarios: Use fakes to test both success and failure cases

#Combining Multiple Fakes

You can use multiple fakes in a single test to isolate all external dependencies:

Mail::fake();
Queue::fake();
Event::fake();
Storage::fake('public');

$this->post('/register', ['name' => 'Jane', 'email' => 'jane@example.com']);

Event::assertDispatched(UserRegistered::class);
Mail::assertSent(WelcomeEmail::class);
Queue::assertPushed(ProcessAvatar::class);

Laravel’s built-in fakes provide a powerful way to test external integrations without complexity. They offer the perfect balance of realistic behavior and test isolation.

Bài viết liên quan