All skills
asyrafhussin avatar

/laravel-testing

@a5fe20e

Laravel 13 testing with Pest PHP 4 or PHPUnit 12. Use when writing feature tests, unit tests, or any test code in a Laravel application. Triggers on tasks involving HTTP tests, model factories, database assertions, mocking facades, authentication testing, or test organisation patterns.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/laravel-testing

This session only. Nothing lands on disk.

rulesfake-mail.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Faking Mail with Mail::fake()

Impact: HIGH (Prevents real emails from being sent in tests and enables assertion on mail behaviour)

Call Mail::fake() before any code that triggers mail. This swaps the mailer with a fake that records calls instead of sending. Always assert both that the correct mailable was sent and that nothing unexpected was sent.

Bad Example

<?php

// Does not fake — sends real emails during tests
test('order confirmation email is sent', function () {
    $order = Order::factory()->create();

    $this->postJson('/api/orders', ['product_id' => 1])
        ->assertStatus(201);
    // No Mail assertion — unknown if email was sent at all
});

// Checks response but ignores side effects
test('user registration triggers welcome email', function () {
    $this->postJson('/api/register', [
        'name'  => 'Alice',
        'email' => 'alice@example.com',
    ])->assertStatus(201);
    // No Mail::fake() — may fire real SMTP in CI
});

Good Example

<?php

use App\Mail\OrderShipped;
use App\Mail\WelcomeEmail;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

// Assert a specific mailable was sent
test('order confirmation is emailed to buyer', function () {
    Mail::fake();

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

    $this->actingAs($user)
        ->postJson('/api/orders', ['product_id' => 1])
        ->assertStatus(201);

    Mail::assertSent(OrderShipped::class);
});

// Assert sent to specific recipient
test('welcome email is sent to new user email address', function () {
    Mail::fake();

    $this->postJson('/api/register', [
        'name'                  => 'Alice',
        'email'                 => 'alice@example.com',
        'password'              => 'secret123',
        'password_confirmation' => 'secret123',
    ])->assertStatus(201);

    Mail::assertSent(WelcomeEmail::class, 'alice@example.com');
});

// Assert nothing was sent for non-triggering actions
test('updating profile does not send an email', function () {
    Mail::fake();

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

    $this->actingAs($user)
        ->patchJson('/api/profile', ['name' => 'Bob'])
        ->assertOk();

    Mail::assertNothingSent();
});

// Assert sent with closure — inspect mailable attributes
test('order email contains the correct order number', function () {
    Mail::fake();

    $user  = User::factory()->create();
    $order = Order::factory()->for($user)->create(['number' => 'ORD-999']);

    $order->ship();

    Mail::assertSent(OrderShipped::class, fn (OrderShipped $mail) =>
        $mail->order->number === 'ORD-999' &&
        $mail->hasTo($user->email)
    );
});

// Assert sent count
test('bulk action sends one email per user', function () {
    Mail::fake();

    User::factory()->count(3)->create();

    $this->postJson('/api/admin/send-newsletter')->assertOk();

    Mail::assertSentTimes(NewsletterMail::class, 3);
});

assertSent vs assertQueued

If the mailable is dispatched via a queued job (Mail::to()->queue()), use assertQueued — assertSent will not see it:

// Mailable sent immediately (Mail::to()->send())
Mail::assertSent(OrderShipped::class);

// Mailable queued for background delivery (Mail::to()->queue())
Mail::assertQueued(OrderShipped::class);

// Not sure? Assert at least one of them
Mail::assertSent(OrderShipped::class);
// or
Mail::assertQueued(OrderShipped::class);

Key Assertions

Method Description
Mail::assertSent(Mailable::class) Mailable was sent immediately
Mail::assertQueued(Mailable::class) Mailable was queued for delivery
Mail::assertSent(Mailable::class, $email) Sent to specific address
Mail::assertSent(Mailable::class, $closure) Sent and closure returns true
Mail::assertNotSent(Mailable::class) Mailable was not sent
Mail::assertNotQueued(Mailable::class) Mailable was not queued
Mail::assertNothingSent() No mailables sent or queued
Mail::assertSentTimes(Mailable::class, $n) Sent exactly N times
Mail::assertSentCount($n) Total mails sent equals N

Why It Matters

  • No side effects: Real emails in CI clutter inboxes and fail in sandboxed environments
  • Behaviour verified: Tests confirm mail is triggered at the right time, to the right address
  • Fast: No SMTP round-trip — tests run at full speed

Reference: Laravel Mocking — Mail Fake

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill is a comprehensive testing guide for Laravel 13, covering both Pest PHP and PHPUnit frameworks. It provides clear rules and code examples for HTTP testing, model factories, database assertions, and mocking services. No security risks or malicious patterns were identified.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    25 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at a5fe20e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
Other metadata
metadata
{
  "author": "Laravel Community",
  "version": "1.1.0",
  "laravelVersion": "13.x",
  "phpVersion": "8.3+",
  "pestVersion": "4.x",
  "phpunitVersion": "12.x"
}

README badge

README badge for asyrafhussin/agent-skills/laravel-testing